mirror of https://github.com/ARMmbed/mbed-os.git
4101 lines
162 KiB
C
4101 lines
162 KiB
C
/** @file configuration_store.c
|
|
*
|
|
* mbed Microcontroller Library
|
|
* Copyright (c) 2006-2016 ARM Limited
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <cfstore_fnmatch.h>
|
|
|
|
#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3
|
|
#include <core-util/critical.h>
|
|
#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */
|
|
#include "cfstore_config.h"
|
|
#ifdef YOTTA_CFG_CFSTORE_UVISOR
|
|
#include "uvisor-lib/uvisor-lib.h"
|
|
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
|
|
#if defined CFSTORE_CONFIG_BACKEND_FLASH_ENABLED && CFSTORE_CONFIG_BACKEND_FLASH_ENABLED == 1
|
|
#include <flash-journal-strategy-sequential/flash_journal_strategy_sequential.h>
|
|
#include <flash-journal/flash_journal.h>
|
|
#include <Driver_Common.h>
|
|
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
|
|
|
|
#include "cfstore_debug.h"
|
|
#include "cfstore_list.h"
|
|
#include "configuration-store/configuration_store.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <inttypes.h>
|
|
|
|
|
|
#ifdef CFSTORE_DEBUG
|
|
uint32_t cfstore_optDebug_g = 1;
|
|
uint32_t cfstore_optLogLevel_g = CFSTORE_LOG_NONE; /*CFSTORE_LOG_NONE|CFSTORE_LOG_ERR|CFSTORE_LOG_DEBUG|CFSTORE_LOG_FENTRY */
|
|
uint32_t cfstore_optLogTracepoint_g = CFSTORE_TP_NONE; /*CFSTORE_TP_NONE|CFSTORE_TP_CLOSE|CFSTORE_TP_CREATE|CFSTORE_TP_DELETE|CFSTORE_TP_FILE|CFSTORE_TP_FIND|CFSTORE_TP_FLUSH|CFSTORE_TP_INIT|CFSTORE_TP_OPEN|CFSTORE_TP_READ|CFSTORE_TP_WRITE|CFSTORE_TP_VERBOSE1|CFSTORE_TP_VERBOSE2|CFSTORE_TP_VERBOSE3|CFSTORE_TP_FENTRY */
|
|
#endif
|
|
|
|
|
|
/*
|
|
* Externs
|
|
*/
|
|
#if defined CFSTORE_CONFIG_BACKEND_FLASH_ENABLED && CFSTORE_CONFIG_BACKEND_FLASH_ENABLED == 1
|
|
extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0);
|
|
ARM_DRIVER_STORAGE *cfstore_storage_drv = &ARM_Driver_Storage_(0);
|
|
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
|
|
|
|
/*
|
|
* Defines
|
|
*
|
|
* CFSTORE_FLASH_STACK_BUF_SIZE
|
|
* when performing flush, if the program_unit <= CFSTORE_FLASH_STACK_BUF_SIZE octets then a
|
|
* stack buffer is used to perform the tail write. Otherwise a buffer is malloced
|
|
*
|
|
* CFSTORE_FLASH_AREA_SIZE_MIN
|
|
* valid sizes of areas should always be greater than the size of the header, and therefore
|
|
* greater than this value, which is defined as smaller than the header size
|
|
*
|
|
* ARM_DRIVER_OK_DONE
|
|
* value that indicates an operation has been done i.e. a value > 0
|
|
*/
|
|
#define CFSTORE_KEY_NAME_CHARS_ACCEPTABLE "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}.-_@"
|
|
#define CFSTORE_KEY_NAME_QUERY_CHARS_ACCEPTABLE CFSTORE_KEY_NAME_CHARS_ACCEPTABLE"*"
|
|
#define CFSTORE_HKVT_REFCOUNT_MAX 0xff
|
|
#define CFSTORE_LOCK_REFCOUNT_MAX 0xffff
|
|
#define CFSTORE_FILE_CREATE_MODE_DEFAULT (ARM_CFSTORE_FMODE)0
|
|
#define CFSTORE_FLASH_STACK_BUF_SIZE 64
|
|
#define CFSTORE_FLASH_AREA_SIZE_MIN (sizeof(cfstore_area_header_t) - 1)
|
|
#define cfstore_fsm_null NULL
|
|
#define CFSTORE_SENTINEL 0x7fffffff
|
|
#define CFSTORE_CALLBACK_RET_CODE_DEFAULT 0x1
|
|
#define ARM_DRIVER_OK_DONE 1
|
|
|
|
/*
|
|
* Simple Types
|
|
*/
|
|
#define CFSTORE_LOCK uint32_t
|
|
|
|
|
|
/*
|
|
* Structures
|
|
*/
|
|
|
|
/** @brief
|
|
*
|
|
* @param key_permissions
|
|
* bottom 6 bits contain the ACLs-bits (owner read/write/execute,
|
|
* other read/write/execute). The remaining bits in this field are
|
|
* used for the Device Data Security Protection Features bit field,
|
|
* bits are low-active
|
|
* @param perm_owner_read
|
|
* if set => this KV is owner readable
|
|
* @param perm_owner_write
|
|
* if set => this KV is owner writable
|
|
* @param perm_owner_execute
|
|
* if set => this KV is owner executable
|
|
* @param perm_other_read
|
|
* if set => this KV is world readable
|
|
* @param perm_other_write
|
|
* if set => this KV is world writable
|
|
* @param perm_other_execute
|
|
* if set => this KV is world executable
|
|
* @param klength
|
|
* key name size including zero-padding
|
|
* @param vlength
|
|
* this value fragment length
|
|
* @param refcount
|
|
* Number of handles open on this hkvt
|
|
*
|
|
* @param delete
|
|
* indicates this KV is being deleted
|
|
*/
|
|
typedef struct cfstore_area_header_t
|
|
{
|
|
uint32_t vlength;
|
|
uint8_t klength;
|
|
uint8_t perm_owner_read : 1;
|
|
uint8_t perm_owner_write : 1;
|
|
uint8_t perm_owner_execute : 1;
|
|
uint8_t perm_other_read : 1;
|
|
uint8_t perm_other_write : 1;
|
|
uint8_t perm_other_execute : 1;
|
|
uint8_t reserved : 2;
|
|
uint8_t refcount;
|
|
struct flags_t {
|
|
uint8_t delete : 1;
|
|
uint8_t reserved : 7;
|
|
} flags ;
|
|
} cfstore_area_header_t;
|
|
|
|
|
|
/* helper struct */
|
|
typedef struct cfstore_area_hkvt_t
|
|
{
|
|
uint8_t *head;
|
|
uint8_t *key;
|
|
uint8_t *value;
|
|
uint8_t *tail;
|
|
} cfstore_area_hkvt_t;
|
|
|
|
|
|
/* helper struct */
|
|
typedef struct cfstore_client_notify_data_t
|
|
{
|
|
uint32_t opcode;
|
|
int32_t status;
|
|
ARM_CFSTORE_HANDLE handle;
|
|
} cfstore_client_notify_data_t;
|
|
|
|
/* @brief test fsm states and events */
|
|
typedef enum cfstore_fsm_state_t {
|
|
cfstore_fsm_state_stopped = 0,
|
|
cfstore_fsm_state_initing,
|
|
cfstore_fsm_state_reading,
|
|
cfstore_fsm_state_logging,
|
|
cfstore_fsm_state_committing,
|
|
cfstore_fsm_state_resetting,
|
|
cfstore_fsm_state_ready, /* ready for next flash journal command to arise */
|
|
cfstore_fsm_state_max
|
|
} cfstore_fsm_state_t;
|
|
|
|
/* @brief test fsm events */
|
|
typedef enum cfstore_fsm_event_t {
|
|
cfstore_fsm_event_init_done = 0,
|
|
cfstore_fsm_event_read_done,
|
|
cfstore_fsm_event_log_done,
|
|
cfstore_fsm_event_commit_req,
|
|
cfstore_fsm_event_commit_done,
|
|
cfstore_fsm_event_reset_done,
|
|
cfstore_fsm_event_max,
|
|
} cfstore_fsm_event_t;
|
|
|
|
typedef int32_t (*cfstore_fsm_handler)(void* ctx);
|
|
|
|
/* @brief flash finite state machine helper function */
|
|
typedef struct cfstore_fsm_t
|
|
{
|
|
cfstore_fsm_state_t state;
|
|
cfstore_fsm_event_t event;
|
|
} cfstore_fsm_t;
|
|
|
|
|
|
#ifdef CFSTORE_DEBUG
|
|
#if defined CFSTORE_CONFIG_BACKEND_FLASH_ENABLED && CFSTORE_CONFIG_BACKEND_FLASH_ENABLED == 1
|
|
/* strings used for debug trace */
|
|
static const char* cfstore_flash_opcode_str[] =
|
|
{
|
|
"FLASH_JOURNAL_OPCODE_INITIALIZE",
|
|
"FLASH_JOURNAL_OPCODE_GET_INFO",
|
|
"FLASH_JOURNAL_OPCODE_READ_BLOB",
|
|
"FLASH_JOURNAL_OPCODE_LOG_BLOB",
|
|
"FLASH_JOURNAL_OPCODE_COMMIT",
|
|
"FLASH_JOURNAL_OPCODE_RESET",
|
|
};
|
|
|
|
static const char* cfstore_flash_state_str[] =
|
|
{
|
|
"stopped",
|
|
"initializing",
|
|
"reading",
|
|
"logging",
|
|
"committing",
|
|
"resetting",
|
|
"ready",
|
|
"unknown"
|
|
};
|
|
|
|
static const char* cfstore_flash_event_str[] =
|
|
{
|
|
"init_done",
|
|
"read_done",
|
|
"log_done",
|
|
"commit_req",
|
|
"commit_done",
|
|
"reset_done",
|
|
"unknown"
|
|
};
|
|
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
|
|
#endif /* CFSTORE_DEBUG */
|
|
|
|
|
|
/*
|
|
* Forward decl
|
|
*/
|
|
#if defined CFSTORE_CONFIG_BACKEND_FLASH_ENABLED && CFSTORE_CONFIG_BACKEND_FLASH_ENABLED == 1
|
|
static int32_t cfstore_fsm_state_handle_event(cfstore_fsm_t* fsm, cfstore_fsm_event_t event, void* context);
|
|
static int32_t cfstore_fsm_state_set(cfstore_fsm_t* fsm, cfstore_fsm_state_t new_state, void* ctx);
|
|
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
|
|
static int32_t cfstore_get_key_name_ex(cfstore_area_hkvt_t *hkvt, char* key_name, uint8_t *key_name_len);
|
|
|
|
|
|
/* Walking Area HKVT's While Inserted a New HKVT:
|
|
* Implementation Note 1 [NOTE1]
|
|
*
|
|
* The implementation must address the following problem:
|
|
* - client1 may be creating a new KV into area_0, which means inserting the
|
|
* header-key-value-tail data into area_0.
|
|
* - concurrently, client2 (through a call to Find()) is walking KVs in area_0,
|
|
* and the walk has to be safe against the insertion of the new KV.
|
|
*
|
|
* This problem is addressed in the by using the cfstore_ctx_g.rw_lock to police
|
|
* access to the area when making changes.
|
|
* - Walking the KVs in area_0 is performed using the header structures,
|
|
* which contain key and value lengths required to find the start of the
|
|
* next hkvt. These must not change under the client.
|
|
* - The Find() walk is terminated when the hkvt header pointer is found to
|
|
* point to cfstore_ctx_g.area_0_tail i.e. when this arises then the
|
|
* iterator knows its come to the end of the hkvt's in the area.
|
|
* - When inserting a new KV, the last operation to be performed is to
|
|
* update cfstore_ctx_g.area_0_tail to point to the new tail. This
|
|
* operation also reveals the new KV to other operations including
|
|
* the Find(). All the header, key, value and tail data for the
|
|
* HKVT must be setup correctly before the tail pointer is updated.
|
|
*
|
|
* Memory Management (todo: future support)
|
|
* Implementation Note 2 [NOTE2]
|
|
* CFSTORE supports using a client provisioned SRAM slab rather than using realloc() to allocated heap
|
|
* memory. This has the following advantages:
|
|
* - the client is in control of the memory allocation.
|
|
* - realloc() cannot fail (e.g. due to memory leaks losing memory) as the sram has been preprovisioned.
|
|
* This makes the system more resilient.
|
|
* The client specifes the sram slab in the following way:
|
|
* - having target.json defined yotta_config.h symbol for CFSTORE_SRAM_START_ADDR, CFSTORE_SRAM_SIZE
|
|
* and #ifdef on these values to use that memory area for area_0 rather than using malloc.
|
|
* - for the case where a client tries to create a KV which causes area_0 to exceed CFSTORE_SRAM_SIZE
|
|
* then the operation is failed.
|
|
* - modify the API so that the client is responsible for allocating the memory the the CFSTORE internal
|
|
* data structures, with the size of the internal data structure exposed through a #define.
|
|
* The contents of the buffer are opaque to the client. The reasons for this are as follows:
|
|
* - to allow the cfstore implementation not to use malloc().
|
|
* - the memory allocation policy for allocating the memory of CFSTORE internal data structures
|
|
* can be decided and implemented by the client
|
|
* - for clients written in C++, its possible to have a static class with the memory for the
|
|
* internal context, and the static class memory area is given to CFSTORE for use, so it
|
|
* provides good C++ support.
|
|
* - The SRAM area can be allocated with the previous point, and the handle associated data
|
|
* structures i.e. cfstore_file_t, can be covered by the supplied buffers to those functions
|
|
* creating handles.
|
|
* - currently neither target.json nor config.json allow a symbol in yotta_config.h to be defined
|
|
* for the current case of CFSTORE being a yotta module/library.
|
|
*
|
|
* UVISOR Integration (todo)
|
|
* Implementation Note 3 [NOTE3]
|
|
* Outstanding Questions:
|
|
* - uvisor_ctx. Should all functions use this to access the global data context?
|
|
* - see cfstore_ctx_get() for an implementation
|
|
* - compile in cfstore_ctx_g only when not using uvisor
|
|
* - how do you allocate heap memory objects with uvisor protections?
|
|
* - doesnt seem to be an api for this yet.
|
|
* - will be required for sram storage of KVs i.e. "the area".
|
|
* - will be required for file objects
|
|
* - Q: is it safe to store the caller_box_id in the cfstore_file_t?
|
|
* A: no, because the cfstore_file_t is held in client controlled memory (opaque hkey)
|
|
* so the client can modify from under cfstore, breaching security if it was used
|
|
* by other cfstore methods.
|
|
* - method for securing access:
|
|
* - create()/open() checks namespace etc, and then creates/opens cfstore_file_t
|
|
* and returns hkey (opaque cfstore_file_t) for subsequent use by api calls.
|
|
* - read/write/rseek etc check the kv pathname accessible via cfstore_file_t::head
|
|
* is within the callers namespace.
|
|
* - we are trusting the caller to be secure and not be malicious?
|
|
* - put "uvisor-lib" : "^2.0.0" in module.json. not necessary as mbed-drivers has this dep.
|
|
* - flash-journal change from using NVIC_Set/GetVector() to VIRQ_Set/GetVector()
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* @brief CS global context that maintains state
|
|
*
|
|
* @param area_0_start
|
|
* pointer to start of malloc-ed memory block for containing area_0
|
|
*
|
|
* @param area_0_head
|
|
* pointer to area_0 header struct within the memblock.
|
|
* - ((cfstore_area_header_t*) area_0)->refcount is the number of
|
|
* open handles in the whole of area_0.
|
|
* - accessed in app & intr context; hence needs CS protection.
|
|
*
|
|
* @param area_0_tail
|
|
* pointer to address in the sram after the last byte of the last
|
|
* KV. Note there can be padding after the area_0_tail to align the
|
|
* sram area with flash program_unit (or 1 if SRAM only version)
|
|
* to facilitate reading/writing to flash.
|
|
* - accessed in app & intr context; hence needs CS protection.
|
|
*
|
|
* @param area_0_end
|
|
* pointer to end area_0 of area_0 memblock (last memory address).
|
|
*
|
|
* @param rw_area0_lock
|
|
* lock used to make CS re-entrant e.g. only 1 flush operation can be
|
|
* performed at a time while no readers/writers have handles open
|
|
* to KVs. The lock is to protect access to the following:
|
|
* - cfstore_ctx_g.area_0_head/cfstore_ctx_g.area_0_tail. Realloc()
|
|
* in Delete() and Create() can cause these pointers to change.
|
|
*
|
|
* @param client_notify_data
|
|
* fsm handler functions set a flag for a client notification call
|
|
* to be made after fsm handler functions have been completed. This
|
|
* block holds the client notification status data for the callback.
|
|
*
|
|
* @param area_dirty_flag
|
|
* flag indicating that the area has been written and therefore is
|
|
* dirty with respect to the data persisted to flash.
|
|
*
|
|
* @expected_blob_size expected_blob_size = area_0_tail - area_0_head + pad
|
|
* In the case of reading from flash into sram, this will be be size
|
|
* of the flash blob (rounded to a multiple program_unit if not
|
|
* already so).
|
|
* In the case of writing to flash, this the size of all the KV's
|
|
* plus padding so the sram blob size is a multiple of flash
|
|
* program_unit.
|
|
* - accessed in app & intr context; hence needs CS protection.
|
|
*/
|
|
typedef struct cfstore_ctx_t
|
|
{
|
|
cfstore_list_node_t file_list;
|
|
int32_t init_ref_count;
|
|
CFSTORE_LOCK rw_area0_lock;
|
|
ARM_POWER_STATE power_state;
|
|
uint8_t *area_0_head;
|
|
uint8_t *area_0_tail;
|
|
cfstore_fsm_t fsm;
|
|
int32_t status;
|
|
|
|
/* client notification data */
|
|
void* client_context;
|
|
ARM_CFSTORE_CALLBACK client_callback;
|
|
cfstore_client_notify_data_t client_notify_data;
|
|
|
|
/* flags */
|
|
uint32_t client_callback_notify_flag : 1;
|
|
uint32_t area_dirty_flag : 1;
|
|
uint32_t f_reserved0 : 30;
|
|
|
|
#if defined CFSTORE_CONFIG_BACKEND_FLASH_ENABLED && CFSTORE_CONFIG_BACKEND_FLASH_ENABLED == 1
|
|
/* flash journal related data */
|
|
FlashJournal_t jrnl;
|
|
FlashJournal_Info_t info;
|
|
FlashJournal_OpCode_t cmd_code;
|
|
uint64_t expected_blob_size;
|
|
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
|
|
} cfstore_ctx_t;
|
|
|
|
|
|
/*
|
|
* @brief file structure for KV, one per open file handle.
|
|
*
|
|
* @param head
|
|
* pointer to head of KV
|
|
*
|
|
* @param rlocation
|
|
* read location of rseek to move
|
|
*
|
|
* @param read
|
|
* indicates file is readable,
|
|
* @param writable
|
|
* indicates file is readable,
|
|
* @param executable
|
|
* indicates file is readable,
|
|
* @param uvisor_client_box_id
|
|
* box id of caller using this file. set on create/open and thereafter used by other methods to check accesses.
|
|
* Q: is it safe to store this here? Is it of any value? i.e. a client can change the value
|
|
* after cfstore has set it so cfstore cant rely on it being secure.
|
|
*/
|
|
typedef struct cfstore_file_t
|
|
{
|
|
cfstore_list_node_t node;
|
|
uint32_t rlocation;
|
|
uint32_t wlocation;
|
|
uint8_t *head;
|
|
ARM_CFSTORE_FMODE flags;
|
|
#ifdef YOTTA_CFG_CFSTORE_UVISOR
|
|
// todo: add this into mix.
|
|
//int uvisor_client_box_id;
|
|
#endif
|
|
|
|
} cfstore_file_t;
|
|
|
|
/* @brief structure used to compose table for mapping flash journal error codes to cfstore error codes */
|
|
typedef struct cfstore_flash_journal_error_code_node
|
|
{
|
|
int32_t flash_journal_error_code;
|
|
int32_t cfstore_error_code;
|
|
} cfstore_flash_journal_error_code_node;
|
|
|
|
|
|
/*
|
|
* Globals
|
|
*/
|
|
#ifndef YOTTA_CFG_CONFIG_HARDWARE_MTD_ASYNC_OPS
|
|
static ARM_CFSTORE_CAPABILITIES cfstore_caps_g = { .asynchronous_ops = 1, .uvisor_support_enabled = 0 };
|
|
#else
|
|
static ARM_CFSTORE_CAPABILITIES cfstore_caps_g = { .asynchronous_ops = YOTTA_CFG_CONFIG_HARDWARE_MTD_ASYNC_OPS, .uvisor_support_enabled = 0 };
|
|
#endif /* YOTTA_CFG_CONFIG_HARDWARE_MTD_ASYNC_OPS */
|
|
|
|
static const ARM_DRIVER_VERSION cfstore_driver_version_g = { .api = ARM_CFSTORE_API_VERSION, .drv = ARM_CFSTORE_DRV_VERSION };
|
|
|
|
#ifndef YOTTA_CFG_CFSTORE_UVISOR
|
|
/* uvisor is not being used so instantiate a context */
|
|
static cfstore_ctx_t cfstore_ctx_g = {
|
|
.file_list.next = NULL,
|
|
.file_list.prev = NULL,
|
|
.init_ref_count = 0,
|
|
.rw_area0_lock = 0,
|
|
.power_state = ARM_POWER_FULL,
|
|
.area_0_head = NULL,
|
|
.area_0_tail = NULL,
|
|
.client_callback = NULL,
|
|
.client_context = NULL,
|
|
.f_reserved0 = 0,
|
|
};
|
|
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
|
|
|
|
#ifdef YOTTA_CFG_CFSTORE_UVISOR
|
|
|
|
/*
|
|
* Configure the secure box compartment
|
|
*/
|
|
static const char const cfstore_uvisor_namespace_root_g[] = "com.arm.mbed.";
|
|
// UVISOR_BOX_NAMESPACE("com.arm.mbed.configuration-store");
|
|
// macro: static const char *const __uvisor_box_namespace = box_namespace
|
|
static const char *const __uvisor_box_namespace = "com.arm.mbed.configuration-store";
|
|
|
|
/* although the descriptor is empty, the main box descriptor is inherited and added to whats here. */
|
|
static const UvisorBoxAclItem cfstore_acl_list_g[] = {
|
|
/* todo: this needs completing with correct data for the secure flash partition above the binary
|
|
*
|
|
0xabaadfood = start of secure flash in address map (flash journal partition
|
|
0xbeefbeef = size in bytes of secure flash partition
|
|
{(void *) 0xabaadfood, 0xbeefbeef, UVISOR_TACLDEF_PERIPH},
|
|
*/
|
|
/* put reference to k64 subfamily reference manual and cmsis k64f target header as to where this comes from */
|
|
{FTFE, sizeof(*FTFE), UVISOR_TACLDEF_PERIPH},
|
|
};
|
|
|
|
/* UVISOR_BOX_CONFIG_CTX(configuration_store, UVISOR_BOX_STACK_SIZE, cfstore_ctx_t);
|
|
*
|
|
* It would be better to use the following macro:
|
|
* UVISOR_BOX_CONFIG(configuration_store, cfstore_acl_list_g, UVISOR_BOX_STACK_SIZE, cfstore_ctx_t);
|
|
* rather than the unpacked macro code that follows.
|
|
*
|
|
* #define __UVISOR_BOX_CONFIG(box_name, acl_list, acl_list_count, stack_size, context_size) \
|
|
* \
|
|
* uint8_t __attribute__((section(".keep.uvisor.bss.boxes"), aligned(32))) \
|
|
* box_name ## _reserved[UVISOR_STACK_SIZE_ROUND(((UVISOR_MIN_STACK(stack_size) + (context_size))*8)/6)]; \
|
|
* \
|
|
* static const __attribute__((section(".keep.uvisor.cfgtbl"), aligned(4))) UvisorBoxConfig box_name ## _cfg = { \
|
|
* UVISOR_BOX_MAGIC, \
|
|
* UVISOR_BOX_VERSION, \
|
|
* UVISOR_MIN_STACK(stack_size), \
|
|
* context_size, \
|
|
* __uvisor_box_namespace, \
|
|
* acl_list, \
|
|
* acl_list_count \
|
|
* }; \
|
|
* \
|
|
* extern const __attribute__((section(".keep.uvisor.cfgtbl_ptr"), aligned(4))) void * const box_name ## _cfg_ptr = &box_name ## _cfg;
|
|
*
|
|
* However, the macro currently generates warnings that need to be fixed i.e.
|
|
* =====================================================================================================================================================================================
|
|
* d:/datastore/public/jobs/yr2016/2247/sdh_dev_10/configuration-store/source/configuration_store.c:490:1: error: initializer element is not constant
|
|
* UVISOR_BOX_CONFIG(configuration_store, cfstore_acl_list_g, UVISOR_BOX_STACK_SIZE, cfstore_ctx_t);
|
|
* ^
|
|
* d:/datastore/public/jobs/yr2016/2247/sdh_dev_10/configuration-store/source/configuration_store.c:490:1: error: (near initialization for 'configuration_store_cfg.box_namespace')
|
|
* In file included from d:/datastore/public/jobs/yr2016/2247/sdh_dev_10/configuration-store/yotta_modules/uvisor-lib/uvisor-lib/uvisor-lib.h:38:0,
|
|
* from d:/datastore/public/jobs/yr2016/2247/sdh_dev_10/configuration-store/source/configuration_store.c:27:
|
|
* d:/datastore/public/jobs/yr2016/2247/sdh_dev_10/configuration-store/source/configuration_store.c:490:19: warning: 'configuration_store_cfg_ptr' initialized and declared 'extern'
|
|
* UVISOR_BOX_CONFIG(configuration_store, cfstore_acl_list_g, UVISOR_BOX_STACK_SIZE, cfstore_ctx_t);
|
|
* ^
|
|
* d:/datastore/public/jobs/yr2016/2247/sdh_dev_10/configuration-store/yotta_modules/uvisor-lib/uvisor-lib/box_config.h:74:95: note: in definition of macro '__UVISOR_BOX_CONFIG'
|
|
* extern const __attribute__((section(".keep.uvisor.cfgtbl_ptr"), aligned(4))) void * const box_name ## _cfg_ptr = &box_name ## _cfg;
|
|
* ^
|
|
* d:/datastore/public/jobs/yr2016/2247/sdh_dev_10/configuration-store/yotta_modules/uvisor-lib/uvisor-lib/box_config.h:57:55: note: in expansion of macro '__UVISOR_BOX_CONFIG_CONTEXT'
|
|
* #define __UVISOR_BOX_MACRO(_1, _2, _3, _4, NAME, ...) NAME
|
|
* ^
|
|
* d:/datastore/public/jobs/yr2016/2247/sdh_dev_10/configuration-store/yotta_modules/uvisor-lib/uvisor-lib/box_config.h:101:5: note: in expansion of macro 'UVISOR_BOX_CONFIG_ACL'
|
|
* UVISOR_BOX_CONFIG_ACL(__VA_ARGS__)
|
|
* ^
|
|
* d:/datastore/public/jobs/yr2016/2247/sdh_dev_10/configuration-store/source/configuration_store.c:490:1: note: in expansion of macro 'UVISOR_BOX_CONFIG'
|
|
* UVISOR_BOX_CONFIG(configuration_store, cfstore_acl_list_g, UVISOR_BOX_STACK_SIZE, cfstore_ctx_t);
|
|
* ^
|
|
* ninja: build stopped: subcommand failed.
|
|
* error: command ['ninja'] failed
|
|
* =====================================================================================================================================================================================
|
|
* The UVISOR_BOX_CONFIG() macro expands to include the following:
|
|
* extern const __attribute__((section(".keep.uvisor.cfgtbl_ptr"), aligned(4))) void * const configuration_store_cfg_ptr = &configuration_store_cfg;
|
|
* The extern at the beginning of the line creates a warning when in a c file, and so needs to be removed/fixed.
|
|
* There are also many other warnings from the macro expansion which need to be investigated further.
|
|
*
|
|
* todo: possible investigation: move configuration_store.c -> configuration_store.cpp
|
|
*/
|
|
uint8_t __attribute__((section(".keep.uvisor.bss.boxes"), aligned(32))) configuration_store_reserved[UVISOR_STACK_SIZE_ROUND(((UVISOR_MIN_STACK(UVISOR_BOX_STACK_SIZE) + (sizeof(cfstore_ctx_t)))*8)/6)];
|
|
static const __attribute__((section(".keep.uvisor.cfgtbl"), aligned(4))) UvisorBoxConfig configuration_store_cfg = {
|
|
UVISOR_BOX_MAGIC,
|
|
UVISOR_BOX_VERSION,
|
|
UVISOR_MIN_STACK(UVISOR_BOX_STACK_SIZE),
|
|
sizeof(cfstore_ctx_t),
|
|
"com.arm.mbed.configuration-store", //problem using__uvisor_box_namespace defined above so inserting string directly here
|
|
cfstore_acl_list_g,
|
|
UVISOR_ARRAY_COUNT(cfstore_acl_list_g)
|
|
};
|
|
|
|
const __attribute__((section(".keep.uvisor.cfgtbl_ptr"), aligned(4))) void * const configuration_store_cfg_ptr = &configuration_store_cfg;
|
|
UVISOR_EXTERN cfstore_ctx_t * const uvisor_ctx;
|
|
|
|
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
|
|
|
|
/*
|
|
* client notifier helper function
|
|
*/
|
|
static void cfstore_client_notify_data_init(cfstore_client_notify_data_t* data, uint32_t opcode, int32_t status, ARM_CFSTORE_HANDLE handle)
|
|
{
|
|
memset(data, 0, sizeof(cfstore_client_notify_data_t));
|
|
data->opcode = opcode;
|
|
data->status = status;
|
|
data->handle = handle;
|
|
}
|
|
|
|
/*
|
|
* cfstore_ctx_t methods
|
|
*/
|
|
|
|
/* @brief helper function to reset cfstore_ctx_g state when out of memory is received from malloc */
|
|
static void cfstore_ctx_reset(cfstore_ctx_t* ctx)
|
|
{
|
|
CFSTORE_ASSERT(ctx!= NULL);
|
|
CFSTORE_INIT_LIST_HEAD(&ctx->file_list);
|
|
ctx->area_0_head = NULL;
|
|
ctx->area_0_tail = NULL;
|
|
return;
|
|
}
|
|
|
|
/* @brief helper function to report whether the initialisation flag has been set in the cfstore_ctx_g */
|
|
static bool cfstore_ctx_is_initialised(cfstore_ctx_t* ctx)
|
|
{
|
|
CFSTORE_ASSERT(ctx!= NULL);
|
|
return ctx->init_ref_count > 0 ? true : false;
|
|
}
|
|
|
|
/* @brief helper function to return a pointer to the global cfstore context. */
|
|
static inline cfstore_ctx_t* cfstore_ctx_get(void)
|
|
{
|
|
#ifdef YOTTA_CFG_CFSTORE_UVISOR
|
|
/* use the secure cfstore_ctx_t struct allocated by uvisor for use */
|
|
return (cfstore_ctx_t*) uvisor_ctx;
|
|
#else
|
|
/* use the insecure statically allocated data struct */
|
|
return &cfstore_ctx_g;
|
|
#endif
|
|
}
|
|
|
|
/* @brief helper function to compute the size of the sram area in bytes */
|
|
static ARM_CFSTORE_SIZE cfstore_ctx_get_area_len(void)
|
|
{
|
|
ARM_CFSTORE_SIZE size = 0;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
|
|
size = (ARM_CFSTORE_SIZE) (ctx->area_0_tail - ctx->area_0_head);
|
|
return size;
|
|
}
|
|
|
|
/* @brief helper function to get the program_unit */
|
|
static inline uint32_t cfstore_ctx_get_program_unit(cfstore_ctx_t* ctx)
|
|
{
|
|
CFSTORE_ASSERT(ctx!= NULL);
|
|
#if defined CFSTORE_CONFIG_BACKEND_FLASH_ENABLED && CFSTORE_CONFIG_BACKEND_FLASH_ENABLED == 1
|
|
return ctx->info.program_unit;
|
|
#else
|
|
/* the program unit is 1 so byte aligned when no flash backend present */
|
|
(void) ctx;
|
|
return 1;
|
|
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
|
|
|
|
}
|
|
|
|
static inline void cfstore_ctx_client_notify(cfstore_ctx_t* ctx, cfstore_client_notify_data_t* data)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered: ctx=%p, ctx->client_callback=%p, ctx->client_context=%p\n", __func__, ctx, ctx->client_callback, ctx->client_context);
|
|
if(ctx->client_callback){
|
|
ctx->client_callback(data->status, (ARM_CFSTORE_OPCODE) data->opcode, ctx->client_context, data->handle);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* CFSTORE_YOTTA_CFG_CFSTORE_SRAM_ADDR
|
|
* client can supply a SRAM slab address and size for
|
|
* CFSTORE internal use. This is a default addr
|
|
* for development use. Should be defined by client
|
|
* CFSTORE_YOTTA_CFG_CFSTORE_SRAM_SIZE
|
|
* size of sram area. Should be define by client
|
|
*/
|
|
#ifndef CFSTORE_YOTTA_CFG_CFSTORE_SRAM_ADDR
|
|
/* if the client doesnt provide a memory slab then CFSTORE uses realloc internally*/
|
|
|
|
#ifndef CFSTORE_DEBUG
|
|
#define CFSTORE_FREE free
|
|
#define CFSTORE_MALLOC malloc
|
|
#define CFSTORE_REALLOC realloc
|
|
#else
|
|
|
|
static uint32_t cfstore_malloc_size_g = 0;
|
|
#define CFSTORE_MALLOC malloc
|
|
|
|
static void* CFSTORE_REALLOC(void *ptr, size_t size)
|
|
{
|
|
void* mem;
|
|
|
|
mem = realloc(ptr, size);
|
|
CFSTORE_TP(CFSTORE_TP_MEM, "%s:ptr=%p, mem=%p, old_size=%u, new_size=%u.\n", __func__, ptr, mem, (int) cfstore_malloc_size_g, (int) size);
|
|
cfstore_malloc_size_g = size;
|
|
return mem;
|
|
}
|
|
|
|
static void CFSTORE_FREE(void *ptr)
|
|
{
|
|
free(ptr);
|
|
CFSTORE_TP(CFSTORE_TP_MEM, "%s:ptr=%p, old_size=%u, new_size=%u.\n", __func__, ptr, (int) cfstore_malloc_size_g, 0);
|
|
cfstore_malloc_size_g = 0;
|
|
return;
|
|
}
|
|
#endif /* CFSTORE_DEBUG */
|
|
|
|
/* memory tracking */
|
|
|
|
#else
|
|
#define CFSTORE_FREE CFSTORE_ASSERT(0)
|
|
#define CFSTORE_MALLOC CFSTORE_ASSERT(0)
|
|
#define CFSTORE_REALLOC cfstore_realloc
|
|
|
|
|
|
|
|
/* function to realloc from a client provided memory slab
|
|
* size = new size of area used by sram
|
|
* ptr is always head of slab
|
|
*
|
|
* The cfstore_realloc() function changes the size of the memory
|
|
* block pointed to by ptr to size bytes, backed by the client
|
|
* provided memory slab. The contents will be unchanged in the
|
|
* range from the start of the region up to the minimum of the
|
|
* old and new sizes. If the new size is larger than the old size,
|
|
* the added memory will not be initialized.
|
|
*
|
|
* ptr
|
|
* ptr should be set to null on the first call to this function and
|
|
* for size > 0 && size <= CFSTORE_YOTTA_CFG_CFSTORE_SRAM_SIZE
|
|
* CFSTORE_YOTTA_CFG_CFSTORE_SRAM_ADDR will be returned.
|
|
* On subsequent calls, ptr must have been returned by an earlier
|
|
* call to this function.
|
|
*
|
|
* size
|
|
* if size is equal to zero, and ptr is not NULL, then the call is
|
|
* equivalent to reseting the memory area and NULL will be returned.
|
|
*/
|
|
void *cfstore_realloc(void *ptr, ARM_CFSTORE_SIZE size)
|
|
{
|
|
static uint8_t *cfstore_sram_head = NULL;
|
|
static uint8_t *cfstore_sram_tail = NULL;
|
|
|
|
if(size > 0) {
|
|
if(size <= CFSTORE_YOTTA_CFG_CFSTORE_SRAM_SIZE) {
|
|
if(ptr == NULL) {
|
|
memset(CFSTORE_YOTTA_CFG_CFSTORE_SRAM_ADDR, 0, CFSTORE_YOTTA_CFG_CFSTORE_SRAM_SIZE);
|
|
cfstore_sram_head = CFSTORE_YOTTA_CFG_CFSTORE_SRAM_ADDR;
|
|
}
|
|
cfstore_sram_tail = cfstore_sram_head + size;
|
|
return (void*) cfstore_sram_head;
|
|
}
|
|
/* requested size is too big so fail the operation by setting
|
|
* head/tail to NULL */
|
|
}
|
|
/* size == 0 => reset */
|
|
cfstore_sram_head = NULL;
|
|
cfstore_sram_tail = NULL;
|
|
return (void*) cfstore_sram_head;
|
|
}
|
|
|
|
#endif /* CFSTORE_YOTTA_CFG_CFSTORE_SRAM_ADDR */
|
|
|
|
/*
|
|
* Platform Specific Function Implementations
|
|
*/
|
|
#ifdef TARGET_LIKE_FRDM_K64F_GCC
|
|
static inline void cfstore_critical_section_init(CFSTORE_LOCK* lock){ *lock = 0; }
|
|
static inline void cfstore_critical_section_unlock(CFSTORE_LOCK* lock, const char* tag)
|
|
{
|
|
(void) lock;
|
|
(void) tag;
|
|
CFSTORE_DBGLOG("%s:before critical_section_exit()(lock=%lu)\n", tag, *lock);
|
|
(*lock)--;
|
|
/* todo: put mbedosv3++ critical section exit here */
|
|
CFSTORE_DBGLOG("%s:after critical_section_exit()(lock=%lu)\n", tag, *lock);
|
|
}
|
|
|
|
static inline void cfstore_critical_section_lock(CFSTORE_LOCK* lock, const char* tag)
|
|
{
|
|
(void) lock;
|
|
(void) tag;
|
|
CFSTORE_DBGLOG("%s:before critical_section_enter()(lock=%lu)\n", tag, *lock);
|
|
/* todo: put mbedosv3++ critical section enter here */
|
|
(*lock)++;
|
|
CFSTORE_DBGLOG("%s:after critical_section_enter()(lock=%lu)\n", tag, *lock);
|
|
}
|
|
|
|
static CFSTORE_INLINE int32_t cfstore_hkvt_refcount_dec(cfstore_area_hkvt_t* hkvt, uint8_t *refcount)
|
|
{
|
|
cfstore_area_header_t *hdr = (cfstore_area_header_t*) hkvt->head;
|
|
|
|
/* todo: put mbedosv3++ critical section enter here */
|
|
hdr->refcount--;
|
|
if(refcount) *refcount = hdr->refcount;
|
|
/* todo: put mbedosv3++ critical section exit here */
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
static CFSTORE_INLINE int32_t cfstore_hkvt_refcount_inc(cfstore_area_hkvt_t* hkvt, uint8_t *refcount)
|
|
{
|
|
int32_t ret = ARM_CFSTORE_DRIVER_ERROR_HANDLE_COUNT_MAX;
|
|
cfstore_area_header_t *hdr = (cfstore_area_header_t*) hkvt->head;
|
|
|
|
/* todo: put mbedosv3++ critical section enter here */
|
|
if(hdr->refcount < CFSTORE_HKVT_REFCOUNT_MAX)
|
|
{
|
|
hdr->refcount++;
|
|
if(refcount) *refcount = hdr->refcount;
|
|
ret = ARM_DRIVER_OK;
|
|
}
|
|
/* todo: put mbedosv3++ critical section exit here */
|
|
return ret;
|
|
}
|
|
#endif /* TARGET_LIKE_FRDM_K64F_GCC */
|
|
|
|
|
|
#ifdef TARGET_LIKE_X86_LINUX_NATIVE
|
|
static inline void cfstore_critical_section_init(CFSTORE_LOCK* lock){ *lock = 0; }
|
|
static inline void cfstore_critical_section_lock(CFSTORE_LOCK* lock, const char* tag){ (void) tag; __sync_fetch_and_add(lock, 1); }
|
|
static inline void cfstore_critical_section_unlock(CFSTORE_LOCK* lock, const char* tag){(void) tag; __sync_fetch_and_sub(lock, 1); }
|
|
|
|
static CFSTORE_INLINE int32_t cfstore_hkvt_refcount_dec(cfstore_area_hkvt_t* hkvt, uint8_t *refcount)
|
|
{
|
|
cfstore_area_header_t *hdr = (cfstore_area_header_t*) hkvt->head;
|
|
uint32_t __refcount;
|
|
|
|
__refcount =__sync_fetch_and_sub(&hdr->refcount, 1);
|
|
if(refcount) *refcount = __refcount;
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
static CFSTORE_INLINE int32_t cfstore_hkvt_refcount_inc(cfstore_area_hkvt_t* hkvt, uint8_t *refcount)
|
|
{
|
|
int32_t ret = ARM_CFSTORE_DRIVER_ERROR_HANDLE_COUNT_MAX;
|
|
uint32_t __refcount;
|
|
cfstore_area_header_t *hdr = (cfstore_area_header_t*) hkvt->head;
|
|
|
|
if( (__refcount = __sync_fetch_and_add(&hdr->refcount, 1)) < CFSTORE_LOCK_REFCOUNT_MAX) {
|
|
if(refcount) *refcount = __refcount;
|
|
ret = ARM_DRIVER_OK;
|
|
} else {
|
|
/* maximum count reach, back down and return error*/
|
|
__sync_fetch_and_sub(&hdr->refcount, 1);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#endif /* TARGET_LIKE_X86_LINUX_NATIVE */
|
|
|
|
|
|
/*
|
|
* security/permissions helper functions
|
|
*/
|
|
#ifdef noCFG_CFSTORE_UVISOR
|
|
|
|
/**
|
|
* @brief check that a client (cfstore-uvisor client box) is the "owner" of the
|
|
* KV. Owner means the client that can create or created the KV. This is
|
|
* determined by the clients namespace and whether the KV path name falls
|
|
* within that name space
|
|
* @param key_name
|
|
* the name of the KV being created.
|
|
* the validation that the key_name is composed of permissible chars is
|
|
* carried out before this function is called.
|
|
* @note
|
|
* Conceptually, cfstore supports the following KV path namespaces:
|
|
* - com.arm.mbed.
|
|
* - guids of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx where x is a hex digit.
|
|
*
|
|
* In the cfstore implementation, explicit checking of the structure of the
|
|
* namespace string is not required. Cfstore only need enforce that:
|
|
* the root of the KV pathname == cfstore client uvisor namespace.
|
|
*/
|
|
static int32_t cfstore_uvisor_is_client_kv_owner(char* key_name, int32_t* cfstore_uvisor_box_id)
|
|
{
|
|
int32_t calling_box_id;
|
|
int32_t ret;
|
|
/* We store the calling_box_namespace on our stack, lest somebody else modify it. */
|
|
char calling_box_namespace[UVISOR_MAX_BOX_NAMESPACE_LENGTH];
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
memset(calling_box_namespace, 0, sizeof(calling_box_namespace));
|
|
/* Get the ID of the box that called this box through the most recent secure gateway. */
|
|
calling_box_id = uvisor_box_id_caller();
|
|
if(calling_box_id < 0){
|
|
CFSTORE_ERRLOG("%s: Error: uvisor uvisor_box_id_caller() returned invalid id (calling_box_id=%" PRId32 "\n", __func__, calling_box_id);
|
|
return ARM_CFSTORE_DRIVER_ERROR_UVISOR_BOX_ID;
|
|
}
|
|
if(cfstore_uvisor_box_id){
|
|
*cfstore_uvisor_box_id = calling_box_id;
|
|
}
|
|
if(calling_box_id == 0){
|
|
/* the cfstore uvisor client is the main box.
|
|
* main box is not allowed to create a key as a client is only permitted to create KVs in their namespace. */
|
|
CFSTORE_ERRLOG("%s: Error: uvisor box id identifies cfstore client cannot create KVs (calling_box_id=%" PRId32 "\n", __func__, calling_box_id);
|
|
return ARM_CFSTORE_DRIVER_ERROR_UVISOR_BOX_ID;
|
|
}
|
|
/* Copy the name of the calling box to our stack. */
|
|
ret = uvisor_box_namespace(calling_box_id, calling_box_namespace, sizeof(calling_box_namespace));
|
|
if(ret < 0){
|
|
/* error */
|
|
CFSTORE_ERRLOG("%s: Error: unable to recover uvisor box namespace\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_UVISOR_NAMESPACE;
|
|
}
|
|
/* check the cfstore client uvisor box namespace is non-trivial */
|
|
if(strlen(calling_box_namespace) == 0){
|
|
CFSTORE_ERRLOG("%s: Error: uvisor box namespace is zero length\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_UVISOR_NAMESPACE;
|
|
}
|
|
/* check that the key name is within the root domain namespace */
|
|
if(strncmp(calling_box_namespace, key_name, sizeof(calling_box_namespace)) != 0) {
|
|
/* The key_name does not fall within the cfstore-uvisor client namespace and therefore the create is not allowed */
|
|
CFSTORE_ERRLOG("%s: Error: key name (%s) is not permitted to be created within client uvisor box namespace (%s) of cfstore client\n", __func__, key_name, calling_box_namespace);
|
|
return ARM_CFSTORE_DRIVER_ERROR_NO_PERMISSIONS;
|
|
}
|
|
/* We've passed all our checks, so we allow the calling box. */
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
|
|
|
|
/**
|
|
* @brief check that the cfstore client (caller, which is a uvisor box)
|
|
* is only trying to access its own namespace.
|
|
*
|
|
* @note This function is the cfstore equivalent of "is_calling_box_allowed"
|
|
*/
|
|
static int32_t cfstore_uvisor_security_context_prefix_check(const char* key_name)
|
|
{
|
|
/*todo: implement : A client uvisor security context should exist with
|
|
* a security_prefix_name that matches the first part of the
|
|
* key_name. Make sure this is the case. */
|
|
|
|
// if the caller is the main box then deny access, as only secure uvisor boxes
|
|
// are permitted to access cfstore.
|
|
|
|
// get box_id of caller
|
|
// get namespace of caller
|
|
// if the keyname is in the namespace then permit, otherwise deny
|
|
|
|
(void) key_name;
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
/* @brief check that a client (cfstore-uvisor client box) is the "owner" of the
|
|
* KV (wrapper). see cfstore_uvisor_is_client_kv_owner() for more details.
|
|
*/
|
|
static int32_t cfstore_is_client_kv_owner(const char* key_name, int32_t* cfstore_uvisor_box_id)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
/*
|
|
#ifdef YOTTA_CFG_CFSTORE_UVISOR
|
|
return cfstore_uvisor_is_client_kv_owner(key_name, cfstore_uvisor_box_id);
|
|
#else
|
|
return ARM_DRIVER_OK;
|
|
#endif
|
|
*/
|
|
(void) key_name;
|
|
(void) cfstore_uvisor_box_id;
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
/* @brief helper function to determine whether this client can close a given KV */
|
|
static bool cfstore_is_kv_client_closable(cfstore_file_t* file)
|
|
{
|
|
/* todo: integrate with uvisor to get boxId (security prefix name)
|
|
* - check the kv key_name prefix matches the security context to determine whether client is
|
|
* allowed to close the given key_name.
|
|
*/
|
|
/* until can implement this functionality, assume client can close KV */
|
|
(void) file;
|
|
return true;
|
|
}
|
|
|
|
/* @brief helper function to determine whether this client can delete a given KV */
|
|
static bool cfstore_is_kv_client_deletable(cfstore_file_t* file)
|
|
{
|
|
/* todo: integrate with uvisor to get boxId (security prefix name)
|
|
* - check the kv key_name prefix matches the security context to determine whether client is
|
|
* allowed to delete the given key_name.
|
|
*/
|
|
/* until can implement this functionality, assume client can delete KV */
|
|
(void) file;
|
|
return true;
|
|
}
|
|
|
|
#ifdef YOTTA_CFG_CFSTORE_UVISOR_to_debug
|
|
/* @brief helper function to determine whether this cfstore-uvisor client box can read a given KV */
|
|
static bool cfstore_is_kv_client_readable(cfstore_area_hkvt_t* hkvt)
|
|
{
|
|
bool bret = false;
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
char key_name[CFSTORE_KEY_NAME_MAX_LENGTH+1];
|
|
uint8_t key_name_len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
|
|
cfstore_area_header_t *hdr = (cfstore_area_header_t*) hkvt->head;
|
|
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
memset(key_name, 0, key_name_len);
|
|
ret = cfstore_get_key_name_ex(hkvt, key_name, &key_name_len);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: cfstore_get_key_name_ex() returned error.\n", __func__);
|
|
return bret;
|
|
}
|
|
ret = cfstore_is_client_kv_owner(key_name, NULL);
|
|
if(ret == ARM_DRIVER_OK){
|
|
/* cfstore-usvisor client box is the "owner" of the key */
|
|
bret = hdr->perm_owner_read;
|
|
} else {
|
|
/* cfstore-usvisor client box is not the "owner" of the key i.e. is the "other" */
|
|
bret = hdr->perm_other_read;
|
|
}
|
|
return bret;
|
|
}
|
|
|
|
/* @brief helper function to determine whether this client can write a given KV */
|
|
static bool cfstore_is_kv_client_writable(cfstore_area_hkvt_t* hkvt)
|
|
{
|
|
bool bret = false;
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
char key_name[CFSTORE_KEY_NAME_MAX_LENGTH+1];
|
|
uint8_t key_name_len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
|
|
cfstore_area_header_t *hdr = (cfstore_area_header_t*) hkvt->head;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
memset(key_name, 0, key_name_len);
|
|
ret = cfstore_get_key_name_ex(hkvt, key_name, &key_name_len);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: cfstore_get_key_name_ex() returned error.\n", __func__);
|
|
return bret;
|
|
}
|
|
ret = cfstore_is_client_kv_owner(key_name, NULL);
|
|
if(ret == ARM_DRIVER_OK){
|
|
/* cfstore-usvisor client box is the "owner" of the key */
|
|
bret = hdr->perm_owner_write;
|
|
} else {
|
|
/* cfstore-usvisor client box is not the "owner" of the key i.e. is the "other" */
|
|
bret = hdr->perm_other_write;
|
|
}
|
|
return bret;
|
|
}
|
|
|
|
/* @brief helper function to determine whether this client can execute a given KV */
|
|
static bool cfstore_is_kv_client_executable(cfstore_area_hkvt_t* hkvt)
|
|
{
|
|
bool bret = false;
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
char key_name[CFSTORE_KEY_NAME_MAX_LENGTH+1];
|
|
uint8_t key_name_len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
|
|
cfstore_area_header_t *hdr = (cfstore_area_header_t*) hkvt->head;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
memset(key_name, 0, key_name_len);
|
|
ret = cfstore_get_key_name_ex(hkvt, key_name, &key_name_len);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: cfstore_get_key_name_ex() returned error.\n", __func__);
|
|
return bret;
|
|
}
|
|
ret = cfstore_is_client_kv_owner(key_name, NULL);
|
|
if(ret == ARM_DRIVER_OK){
|
|
/* cfstore-usvisor client box is the "owner" of the key */
|
|
bret = hdr->perm_owner_execute;
|
|
} else {
|
|
/* cfstore-usvisor client box is not the "owner" of the key i.e. is the "other" */
|
|
bret = hdr->perm_other_execute;
|
|
}
|
|
return bret;
|
|
}
|
|
#endif // YOTTA_CFG_CFSTORE_UVISOR_to_debug
|
|
|
|
/* @brief helper function to determine whether this client can read a given KV */
|
|
static bool cfstore_is_kv_client_readable(cfstore_area_hkvt_t* hkvt)
|
|
{
|
|
/* todo: integrate with uvisor to get boxId (security prefix name)
|
|
* - check the kv key_name prefix matches the security context to determine whether client is
|
|
* owner or other.
|
|
* - if(owner)
|
|
* {
|
|
* // client is owner of kv
|
|
* if( ((cfstore_area_header_t*)(hkvt->head))->perm_owner_read == true) {
|
|
* return true;
|
|
* }
|
|
* } else {
|
|
* // client is other
|
|
* if( ((cfstore_area_header_t*)(hkvt->head))->perm_other_read == true) {
|
|
* return true;
|
|
* }
|
|
* return false;
|
|
*/
|
|
/* until can implement this functionality, assume client has read access to KV */
|
|
(void) hkvt;
|
|
return true;
|
|
}
|
|
|
|
/* @brief helper function to determine whether this client can write a given KV */
|
|
static bool cfstore_is_kv_client_writable(cfstore_area_hkvt_t* hkvt)
|
|
{
|
|
cfstore_area_header_t *hdr = (cfstore_area_header_t*) hkvt->head;
|
|
|
|
/* todo: integrate with uvisor to get boxId (security prefix name)
|
|
* - check the kv key_name prefix matches the security context to determine whether client is
|
|
* owner or other.
|
|
* - if(owner)
|
|
* {
|
|
* // client is owner of kv
|
|
* if( ((cfstore_area_header_t*)(hkvt->head))->perm_owner_write == true) {
|
|
* return true;
|
|
* }
|
|
* } else {
|
|
* // client is other
|
|
* if( ((cfstore_area_header_t*)(hkvt->head))->perm_other_write == true) {
|
|
* return true;
|
|
* }
|
|
* return false;
|
|
*/
|
|
/* until can implement this functionality, assume client has write access to KV */
|
|
|
|
/* check that the owner has write permission */
|
|
return hdr->perm_owner_write;
|
|
}
|
|
|
|
/* @brief helper function to determine whether this client can execute a given KV */
|
|
static bool cfstore_is_kv_client_executable(cfstore_area_hkvt_t* hkvt)
|
|
{
|
|
/* todo: integrate with uvisor to get boxId (security prefix name)
|
|
* - check the kv key_name prefix matches the security context to determine whether client is
|
|
* owner or other.
|
|
* - if(owner)
|
|
* {
|
|
* // client is owner of kv
|
|
* if( ((cfstore_area_header_t*)(hkvt->head))->perm_owner_execute == true) {
|
|
* return true;
|
|
* }
|
|
* } else {
|
|
* // client is other
|
|
* if( ((cfstore_area_header_t*)(hkvt->head))->perm_other_execute == true) {
|
|
* return true;
|
|
* }
|
|
* return false;
|
|
*/
|
|
/* until can implement this functionality, assume client has execute access to KV */
|
|
(void) hkvt;
|
|
return true;
|
|
}
|
|
|
|
|
|
/*
|
|
* flags helper function
|
|
*/
|
|
static bool cfstore_acl_is_default(ARM_CFSTORE_ACCESS_CONTROL_LIST acl)
|
|
{
|
|
if( acl.perm_owner_read == false &&
|
|
acl.perm_owner_write == false &&
|
|
acl.perm_owner_execute == false &&
|
|
acl.perm_other_read == false &&
|
|
acl.perm_other_write == false &&
|
|
acl.perm_other_execute == false )
|
|
{
|
|
/* flags are set to indicate "adopt some meaningful default behaviour" */
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* flags helper function
|
|
*/
|
|
static bool cfstore_flags_is_default(ARM_CFSTORE_FMODE flags)
|
|
{
|
|
if( flags.read == 0 &&
|
|
flags.write == 0 &&
|
|
flags.continuous == 0 &&
|
|
flags.flush_on_close == 0 &&
|
|
flags.lazy_flush == 0 &&
|
|
flags.storage_detect == 0 )
|
|
{
|
|
/* flags are set to indicate "adopt some meaningful default behaviour" */
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static CFSTORE_INLINE bool cfstore_hkvt_get_flags_delete(cfstore_area_hkvt_t *hkvt)
|
|
{
|
|
return ((cfstore_area_header_t*) hkvt->head)->flags.delete;
|
|
}
|
|
|
|
static CFSTORE_INLINE void cfstore_hkvt_set_flags_delete(cfstore_area_hkvt_t *hkvt, bool flag)
|
|
{
|
|
CFSTORE_ASSERT(hkvt != NULL);
|
|
((cfstore_area_header_t*) hkvt->head)->flags.delete = flag;
|
|
}
|
|
|
|
|
|
/*
|
|
* struct cfstore_area_hkvt_t helper operations
|
|
*/
|
|
static CFSTORE_INLINE uint8_t cfstore_hkvt_get_key_len(cfstore_area_hkvt_t* hkvt)
|
|
{
|
|
cfstore_area_header_t *header;
|
|
CFSTORE_ASSERT(hkvt != NULL);
|
|
header = (cfstore_area_header_t*) hkvt->head;
|
|
return header->klength;
|
|
}
|
|
|
|
static CFSTORE_INLINE uint32_t cfstore_hkvt_get_value_len(cfstore_area_hkvt_t* hkvt)
|
|
{
|
|
cfstore_area_header_t *header;
|
|
CFSTORE_ASSERT(hkvt != NULL);
|
|
header = (cfstore_area_header_t*) hkvt->head;
|
|
return header->vlength;
|
|
}
|
|
|
|
static CFSTORE_INLINE ARM_CFSTORE_SIZE cfstore_hkvt_get_size(cfstore_area_hkvt_t* hkvt)
|
|
{
|
|
ARM_CFSTORE_SIZE kv_size = 0;
|
|
|
|
kv_size += sizeof(cfstore_area_header_t);
|
|
kv_size += cfstore_hkvt_get_key_len(hkvt);
|
|
kv_size += cfstore_hkvt_get_value_len(hkvt);
|
|
return kv_size;
|
|
}
|
|
|
|
static CFSTORE_INLINE void cfstore_hkvt_init(cfstore_area_hkvt_t* hkvt)
|
|
{
|
|
memset(hkvt, 0, sizeof(cfstore_area_hkvt_t));
|
|
}
|
|
|
|
|
|
static CFSTORE_INLINE bool cfstore_hkvt_is_valid(cfstore_area_hkvt_t *hkvt, uint8_t *area_0_tail)
|
|
{
|
|
if(hkvt->head && hkvt->head != area_0_tail && hkvt->key && hkvt->value && hkvt->tail) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static CFSTORE_INLINE uint32_t cfstore_hkvt_set_value_len(cfstore_area_hkvt_t* hkvt, uint32_t value_len)
|
|
{
|
|
uint32_t vlength;
|
|
cfstore_area_header_t *hdr;
|
|
CFSTORE_ASSERT(hkvt != NULL);
|
|
hdr = (cfstore_area_header_t*) hkvt->head;
|
|
vlength = hdr->vlength;
|
|
hdr->vlength = value_len;
|
|
return vlength;
|
|
}
|
|
|
|
/* @brief helper function to detect if there are any KV's stored in the sram area */
|
|
static bool cfstore_area_has_hkvt(void)
|
|
{
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
|
|
/* head and tail pointer equal means there are no KVs stored */
|
|
if(ctx->area_0_head == ctx->area_0_tail){
|
|
/* there are no KV's stored*/
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/* @brief helper function to get the first KV in the sram area */
|
|
static cfstore_area_hkvt_t cfstore_get_hkvt_from_head_ptr(uint8_t* head)
|
|
{
|
|
cfstore_area_hkvt_t hkvt;
|
|
|
|
CFSTORE_ASSERT(head != NULL);
|
|
memset((void*) &hkvt, 0, sizeof(hkvt));
|
|
hkvt.head = head;
|
|
hkvt.key = hkvt.head + sizeof(cfstore_area_header_t);
|
|
hkvt.value = hkvt.key + ((cfstore_area_header_t*) hkvt.head)->klength;
|
|
hkvt.tail = hkvt.value + ((cfstore_area_header_t*) hkvt.head)->vlength;
|
|
return hkvt;
|
|
}
|
|
|
|
|
|
/* @brief helper function to convert a opaque handle to a struct cfstore_area_hkvt_t */
|
|
static cfstore_area_hkvt_t cfstore_get_hkvt(ARM_CFSTORE_HANDLE hkey)
|
|
{
|
|
cfstore_file_t* file = (cfstore_file_t*) hkey;
|
|
return cfstore_get_hkvt_from_head_ptr((uint8_t*) file->head);
|
|
}
|
|
|
|
|
|
/* @brief helper function to convert a opaque handle to a struct cfstore_area_hkvt_t */
|
|
static int32_t cfstore_get_head_hkvt(cfstore_area_hkvt_t* hkvt)
|
|
{
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
CFSTORE_ASSERT(hkvt != NULL);
|
|
if(!cfstore_area_has_hkvt()){
|
|
CFSTORE_TP(CFSTORE_TP_VERBOSE1, "%s:CFSTORE has no KVs\n", __func__);
|
|
memset((void*) hkvt, 0, sizeof(cfstore_area_hkvt_t));
|
|
return ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND;
|
|
}
|
|
|
|
CFSTORE_TP(CFSTORE_TP_VERBOSE1, "%s:CFSTORE has KVs\n", __func__);
|
|
*hkvt = cfstore_get_hkvt_from_head_ptr(ctx->area_0_head);
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
|
|
/* @brief helper function to walk the sram area from the previous hkvt to
|
|
* the next hkvt.
|
|
* @param prev
|
|
* pointer to previous hkvt. If null then the search is started
|
|
* from the beginning of the sram area.
|
|
* @param next
|
|
* pointer to next hkvt for which the pointers need calculating.
|
|
*/
|
|
static int32_t cfstore_get_next_hkvt(cfstore_area_hkvt_t* prev, cfstore_area_hkvt_t* next)
|
|
{
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
|
|
CFSTORE_ASSERT(prev != NULL);
|
|
CFSTORE_ASSERT(next != NULL);
|
|
|
|
if(prev->tail == ctx->area_0_tail){
|
|
CFSTORE_TP(CFSTORE_TP_VERBOSE1, "%s:reached the end of the list. return NULL entry\n", __func__);
|
|
memset((void*) next, 0, sizeof(cfstore_area_hkvt_t));
|
|
return ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND;
|
|
}
|
|
/* use the prev tail pointer to find the next head pointer */
|
|
*next = cfstore_get_hkvt_from_head_ptr((uint8_t*) prev->tail);
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
|
|
/*
|
|
* Flash support functions
|
|
*/
|
|
|
|
static CFSTORE_INLINE void cfstore_hkvt_dump(cfstore_area_hkvt_t* hkvt, const char* tag);
|
|
|
|
/* set the tail pointer */
|
|
static int32_t cfstore_flash_set_tail(void)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
uint8_t* ptr = NULL;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
uint8_t* tail = NULL;
|
|
cfstore_area_hkvt_t hkvt;
|
|
|
|
/* walk the area to find the last KV */
|
|
CFSTORE_FENTRYLOG("%s:entered: \n", __func__);
|
|
CFSTORE_ASSERT(ctx != NULL);
|
|
cfstore_hkvt_init(&hkvt);
|
|
ptr = ctx->area_0_head;
|
|
/* ctx->area_0_tail has been set to the end of the sram area allocated, but this is now refined so
|
|
* as to point to the end of the last KV */
|
|
tail = ctx->area_0_tail;
|
|
while(ptr < tail) {
|
|
hkvt = cfstore_get_hkvt_from_head_ptr(ptr);
|
|
cfstore_hkvt_dump(&hkvt, __func__);
|
|
/* when the length between the hkvt.tail and tail (set to the end of the area including padding)
|
|
* is less than the minimum KV length then we have found the last KV, and can set the
|
|
* area_0_tail correctly to the end of the last KV */
|
|
if((uint32_t)(tail - hkvt.tail) < sizeof(cfstore_area_header_t)){
|
|
/* ptr is last KV in area as there isn't space for another header */
|
|
ctx->area_0_tail = hkvt.tail;
|
|
ret = ARM_DRIVER_OK;
|
|
break;
|
|
}
|
|
ptr = hkvt.tail;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#if defined CFSTORE_CONFIG_BACKEND_FLASH_ENABLED && CFSTORE_CONFIG_BACKEND_FLASH_ENABLED == 1
|
|
|
|
/*
|
|
* flash helper functions
|
|
*/
|
|
|
|
/* @brief table for mapping flash journal error codes to equivalent cfstore error codes */
|
|
static cfstore_flash_journal_error_code_node cfstore_flash_journal_error_code_map[]=
|
|
{
|
|
{ JOURNAL_STATUS_OK, ARM_DRIVER_OK},
|
|
{ JOURNAL_STATUS_ERROR, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_ERROR},
|
|
{ JOURNAL_STATUS_BUSY, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_BUSY},
|
|
{ JOURNAL_STATUS_TIMEOUT, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_TIMEOUT},
|
|
{ JOURNAL_STATUS_UNSUPPORTED, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_UNSUPPORTED},
|
|
{ JOURNAL_STATUS_PARAMETER, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_PARAMETER},
|
|
{ JOURNAL_STATUS_BOUNDED_CAPACITY, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_BOUNDED_CAPACITY},
|
|
{ JOURNAL_STATUS_STORAGE_API_ERROR, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_STORAGE_API_ERROR},
|
|
{ JOURNAL_STATUS_STORAGE_IO_ERROR, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_STORAGE_IO_ERROR},
|
|
{ JOURNAL_STATUS_NOT_INITIALIZED, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_NOT_INITIALIZED},
|
|
{ JOURNAL_STATUS_EMPTY, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_EMPTY},
|
|
{ JOURNAL_STATUS_SMALL_LOG_REQUEST, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_SMALL_LOG_REQUEST},
|
|
{ CFSTORE_SENTINEL, CFSTORE_SENTINEL}
|
|
};
|
|
|
|
static int32_t cfstore_flash_map_error(int32_t flash_journal_status_code)
|
|
{
|
|
cfstore_flash_journal_error_code_node* node = cfstore_flash_journal_error_code_map;
|
|
|
|
while(node->flash_journal_error_code != (int32_t) CFSTORE_SENTINEL)
|
|
{
|
|
if(flash_journal_status_code == node->flash_journal_error_code)
|
|
{
|
|
return node->cfstore_error_code;
|
|
}
|
|
}
|
|
return ARM_CFSTORE_DRIVER_ERROR_INTERNAL;
|
|
}
|
|
|
|
|
|
/* @brief Callback registered with flash journal for async operation
|
|
* completion notifications.
|
|
*
|
|
* @note The callback is called at interrupt context.
|
|
* The critical section to used police access to context variables
|
|
* modified by both the interrupt and application context processing.
|
|
* The interrupt context prevents application context from running and
|
|
* hence its only necessary to use the critical_section_xxx in the
|
|
* application execution context.
|
|
*
|
|
* In flash journal async mode, when:
|
|
* - a FlashJournal_xxx() function has been invoked, and
|
|
* - before the async completion has been received and processed
|
|
* the application context code should alway co-ordinate access to
|
|
* context variables modified by interrupt and application context
|
|
* by use of the critical_section_xxx.
|
|
*/
|
|
static void cfstore_flash_journal_callback(int32_t status, FlashJournal_OpCode_t cmd_code)
|
|
{
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered: status=%d, cmd_code=%d (%s)\n", __func__, (int) status, (int) cmd_code, cfstore_flash_opcode_str[cmd_code]);
|
|
switch(cmd_code)
|
|
{
|
|
case FLASH_JOURNAL_OPCODE_INITIALIZE:
|
|
ctx->fsm.event = cfstore_fsm_event_init_done;
|
|
break;
|
|
case FLASH_JOURNAL_OPCODE_READ_BLOB:
|
|
ctx->fsm.event = cfstore_fsm_event_read_done;
|
|
break;
|
|
case FLASH_JOURNAL_OPCODE_LOG_BLOB:
|
|
ctx->fsm.event = cfstore_fsm_event_log_done;
|
|
break;
|
|
case FLASH_JOURNAL_OPCODE_COMMIT:
|
|
ctx->fsm.event = cfstore_fsm_event_commit_done;
|
|
break;
|
|
case FLASH_JOURNAL_OPCODE_RESET:
|
|
ctx->fsm.event = cfstore_fsm_event_reset_done;
|
|
break;
|
|
case FLASH_JOURNAL_OPCODE_GET_INFO:
|
|
default:
|
|
CFSTORE_ERRLOG("%s:Error: notification of unsupported cmd_code event (status=%d, cmd_code=%d)\n", __func__, (int) status, (int) cmd_code);
|
|
return;
|
|
}
|
|
ctx->status = status;
|
|
ctx->cmd_code = cmd_code;
|
|
cfstore_fsm_state_handle_event(&ctx->fsm, ctx->fsm.event, (void*) ctx);
|
|
return;
|
|
}
|
|
|
|
|
|
/* @brief */
|
|
static int32_t cfstore_fsm_stop_on_entry(void* context)
|
|
{
|
|
cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
|
|
|
|
/* reset fsm state */
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
CFSTORE_ASSERT(ctx->fsm.state == cfstore_fsm_state_stopped);
|
|
|
|
ctx->fsm.event = cfstore_fsm_event_max;
|
|
ctx->cmd_code = (FlashJournal_OpCode_t)((int) FLASH_JOURNAL_OPCODE_RESET+1);
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
/* static int32_t cfstore_fsm_stop_on_exit(void* context) {(void) context; }*/
|
|
|
|
|
|
/* @brief fsm on entry function for the initing state
|
|
* @note
|
|
* flash journal sync mode: (see async mode notes)
|
|
* flash journal async mode:
|
|
* This is typically called in app context (not intr context) for both flash
|
|
* journal sync and asyc modes. There are no outstanding async requests
|
|
* so it cannot be interrupted, and therefore doesnt need CS protection.
|
|
*/
|
|
static int32_t cfstore_fsm_init_on_entry(void* context)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_(0);
|
|
cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
|
|
ret = FlashJournal_initialize(&ctx->jrnl, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, cfstore_flash_journal_callback);
|
|
CFSTORE_FENTRYLOG("%s:here\n", __func__);
|
|
CFSTORE_TP(CFSTORE_TP_FSM, "%s:FlashJournal_initialize ret=%" PRId32 "\n", __func__, ret);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: failed to initialize flash journaling layer (ret=%" PRId32 ")\n", __func__, ret);
|
|
cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_stopped, ctx);
|
|
}
|
|
else if(ret > 0){
|
|
/* operation completed synchronously*/
|
|
cfstore_flash_journal_callback(ret, FLASH_JOURNAL_OPCODE_INITIALIZE);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* @brief fsm initing state handler function
|
|
* @note
|
|
* flash journal sync mode:
|
|
* CS protection not required as there are no callbacks.
|
|
* flash journal async mode:
|
|
* This is typically called at intr context (not app context) when flash
|
|
* journal invokes the callback handler for FLASH_JOURNAL_OPCODE_INITIALIZE
|
|
* Hence as running at intr level, no CS protection is required.
|
|
*/
|
|
static int32_t cfstore_fsm_initing(void* context)
|
|
{
|
|
int32_t ret = ARM_DRIVER_OK;
|
|
cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
CFSTORE_ASSERT(ctx->fsm.state == cfstore_fsm_state_initing);
|
|
CFSTORE_ASSERT(ctx->cmd_code == FLASH_JOURNAL_OPCODE_INITIALIZE);
|
|
|
|
/* only change state if status > 0*/
|
|
if(ctx->status > 0){
|
|
ret = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_reading, ctx);
|
|
} else if(ctx->status < 0) {
|
|
CFSTORE_ERRLOG("%s:Error: failed to initialize flash journaling layer (ret=%" PRId32 ")\n", __func__, ctx->status);
|
|
cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_stopped, ctx);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* static int32_t cfstore_fsm_init_on_exit(void* context) */
|
|
|
|
|
|
/* @brief fsm on entry function for the reading state
|
|
* @note
|
|
* flash journal sync mode:
|
|
* CS protection not required as there are no callbacks.
|
|
* flash journal async mode:
|
|
* This is typically called at intr context (not app context) when flash
|
|
* journal invokes the callback handler for FLASH_JOURNAL_OPCODE_INITIALIZE
|
|
* Hence as running at intr level, no CS protection is required.
|
|
*/
|
|
static int32_t cfstore_fsm_read_on_entry(void* context)
|
|
{
|
|
uint8_t* ptr = NULL;
|
|
int32_t ret = 0;
|
|
FlashJournal_Status_t status = JOURNAL_STATUS_ERROR;
|
|
cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
CFSTORE_ASSERT(ctx != NULL);
|
|
/* FlashJournal_getInfo() is synchronous */
|
|
status = FlashJournal_getInfo(&ctx->jrnl, &ctx->info);
|
|
if(status < JOURNAL_STATUS_OK){
|
|
CFSTORE_TP(CFSTORE_TP_FSM, "%s:Error: failed get journal info (status=%d)\n", __func__, (int) status);
|
|
/* move to ready state. cfstore client is expected to Uninitialize() before further calls */
|
|
cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_INTERNAL;
|
|
goto out;
|
|
|
|
}
|
|
if(ctx->info.sizeofJournaledBlob > 0)
|
|
{
|
|
/* setup the expected blob size for writing
|
|
* This is a multiple of program unit so the write doesnt fail due to unaligned log */
|
|
ctx->expected_blob_size = ctx->info.sizeofJournaledBlob;
|
|
if(ctx->expected_blob_size % ctx->info.program_unit > 0){
|
|
ctx->expected_blob_size += (ctx->info.program_unit - (ctx->info.sizeofJournaledBlob % ctx->info.program_unit));
|
|
}
|
|
/* grow the area by the size of the stored blob */
|
|
ptr = (uint8_t*) CFSTORE_REALLOC((void*) ctx->area_0_head, ctx->expected_blob_size);
|
|
if(ptr == NULL){
|
|
CFSTORE_ERRLOG("%s:Error: unable to allocate memory (size=%lu)\n", __func__, (long unsigned int) ctx->info.sizeofJournaledBlob);
|
|
cfstore_ctx_reset(ctx);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_OUT_OF_MEMORY;
|
|
/* move to ready state. cfstore client is expected to Uninitialize() before further calls */
|
|
cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
|
|
goto out;
|
|
}
|
|
memset(ptr, 0, ctx->expected_blob_size);
|
|
if(ptr != ctx->area_0_head){
|
|
CFSTORE_TP(CFSTORE_TP_FSM, "%s:cfstore_ctx_g.area_0_head pointer changed (cfstore_ctx_g.area_0_head=%p, ptr=%p)\n", __func__, ctx->area_0_head, ptr);
|
|
ctx->area_0_head = ptr;
|
|
ctx->area_0_tail = ctx->area_0_head + ctx->info.sizeofJournaledBlob;
|
|
}
|
|
ret = FlashJournal_read(&ctx->jrnl, (void*) ctx->area_0_head, ctx->info.sizeofJournaledBlob);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: failed to initialize flash journaling layer (ret=%d)\n", __func__, (int) ret);
|
|
/* move to ready state. cfstore client is expected to Uninitialize() before further calls */
|
|
cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
|
|
goto out;
|
|
} else if(ret > 0){
|
|
/* read has completed synchronously*/
|
|
CFSTORE_TP(CFSTORE_TP_FSM, "%s:debug:ret > 0: (ret=%d)\n", __func__, (int) ret);
|
|
cfstore_flash_journal_callback(ret, FLASH_JOURNAL_OPCODE_READ_BLOB);
|
|
ret = ctx->status;
|
|
goto out;
|
|
}
|
|
/* keep lock and wait for async callback */
|
|
} else {
|
|
/* there is no blob, move to next state. need a +ve status value to indicate async completion
|
|
* to the fsm reading state handler. use CFSTORE_FLASH_AREA_SIZE_MIN for this value */
|
|
ctx->expected_blob_size = CFSTORE_FLASH_AREA_SIZE_MIN;
|
|
status = (FlashJournal_Status_t) CFSTORE_FLASH_AREA_SIZE_MIN;
|
|
cfstore_flash_journal_callback(status, FLASH_JOURNAL_OPCODE_READ_BLOB);
|
|
ret = ctx->status;
|
|
goto out;
|
|
}
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* @brief fsm handler when in reading state */
|
|
static int32_t cfstore_fsm_reading(void* context)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
CFSTORE_ASSERT(ctx->fsm.state == cfstore_fsm_state_reading);
|
|
CFSTORE_ASSERT(ctx->cmd_code == FLASH_JOURNAL_OPCODE_READ_BLOB);
|
|
if(ctx->status > 0)
|
|
{
|
|
if(ctx->status > (int32_t) CFSTORE_FLASH_AREA_SIZE_MIN)
|
|
{
|
|
CFSTORE_TP(CFSTORE_TP_FSM, "%s:debug:ctx->status > (int32_t) CFSTORE_FLASH_AREA_SIZE_MIN:\n", __func__);
|
|
/* check the correct amount of data was read, which is the status code */
|
|
if(ctx->status == (int32_t) ctx->expected_blob_size)
|
|
{
|
|
/* now have to allow for the fact that there may have been some padding
|
|
* at the end of the last _log() to flash, so the read back area may have
|
|
* padding at the end, and the tail_pointer needs to not point to the
|
|
* end where the padding is located, but to the end of the last KV.
|
|
*/
|
|
ret = cfstore_flash_set_tail();
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: cfstore_flash_set_tail() failed (ret=%" PRId32 ")\n", __func__, ret);
|
|
/* move to ready state. cfstore client is expected to Uninitialize() before further calls */
|
|
cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
|
|
memset(&ctx->info, 0, sizeof(ctx->info));
|
|
goto out;
|
|
}
|
|
/* clear info data */
|
|
memset(&ctx->info, 0, sizeof(ctx->info));
|
|
ret = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: cfstore_fsm_state_set() failed (ret=%" PRId32 ")\n", __func__, ret);
|
|
goto out;
|
|
}
|
|
ret = ctx->status;
|
|
}
|
|
else
|
|
{
|
|
CFSTORE_ERRLOG("%s:Error: read bytes (%d) does not equal requested read size (%d)\n", __func__, (int) ctx->status, (int) ctx->expected_blob_size);
|
|
ret = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
|
|
if(ret < ARM_DRIVER_OK){
|
|
/* move to ready state. cfstore client is expected to Uninitialize() before further calls */
|
|
CFSTORE_ERRLOG("%s:Error: cfstore_fsm_state_set() failed (ret=%" PRId32 ")\n", __func__, ret);
|
|
goto out;
|
|
}
|
|
ret = ctx->status;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CFSTORE_TP(CFSTORE_TP_FSM, "%s:debug:ctx->status <= (int32_t) CFSTORE_FLASH_AREA_SIZE_MIN:\n", __func__);
|
|
ret = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
|
|
if(ret < ARM_DRIVER_OK){
|
|
/* move to ready state. cfstore client is expected to Uninitialize() before further calls */
|
|
CFSTORE_ERRLOG("%s:Error: cfstore_fsm_state_set() failed (ret=%" PRId32 ")\n", __func__, ret);
|
|
goto out;
|
|
}
|
|
ret = ctx->status;
|
|
}
|
|
}
|
|
else if(ctx->status < 0)
|
|
{
|
|
CFSTORE_TP(CFSTORE_TP_FSM, "%s:debug:ctx->status < 0:\n", __func__);
|
|
ret = ctx->status;
|
|
}
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int32_t cfstore_fsm_read_on_exit(void* context)
|
|
{
|
|
cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered:\n", __func__);
|
|
/* notify client of initialisation status */
|
|
cfstore_client_notify_data_init(&ctx->client_notify_data, CFSTORE_OPCODE_INITIALIZE, ctx->status, NULL);
|
|
ctx->client_callback_notify_flag = true;
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
/* int32_t cfstore_fsm_log_on_entry(void* context){ (void) context;} */
|
|
|
|
/* @brief on entry to writing state, update value */
|
|
int32_t cfstore_fsm_log_on_entry(void* context)
|
|
{
|
|
int32_t ret = 0;
|
|
cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
|
|
FlashJournal_Info_t info;
|
|
FlashJournal_Status_t status = JOURNAL_STATUS_ERROR;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered:\n", __func__);
|
|
memset(&info, 0, sizeof(info));
|
|
|
|
status = FlashJournal_getInfo(&ctx->jrnl, &info);
|
|
if(status < JOURNAL_STATUS_OK){
|
|
CFSTORE_ERRLOG("%s:Error: failed get journal info (status=%d)\n", __func__, (int) status);
|
|
/* move to ready state. cfstore client is expected to Uninitialize() before further calls */
|
|
cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
|
|
return cfstore_flash_map_error(status);
|
|
}
|
|
/* compute the expected_blob_size = area_size plus the padding at the end of the area to align with program_unit*/
|
|
ctx->expected_blob_size = cfstore_ctx_get_area_len();
|
|
if(ctx->expected_blob_size % info.program_unit > 0){
|
|
ctx->expected_blob_size += (info.program_unit - (ctx->expected_blob_size % info.program_unit));
|
|
}
|
|
if(ctx->area_0_head && ctx->area_dirty_flag == true)
|
|
{
|
|
ret = FlashJournal_log(&ctx->jrnl, (const void*) ctx->area_0_head, ctx->expected_blob_size);
|
|
if(ret < JOURNAL_STATUS_OK){
|
|
CFSTORE_ERRLOG("%s:Error: FlashJournal_commit() failed (ret=%d)\n", __func__, (int) ret);
|
|
ret = cfstore_flash_map_error(status);
|
|
/* move to ready state. cfstore client is expected to Uninitialize() before further calls */
|
|
cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
|
|
goto out0;
|
|
} else if(ret > 0){
|
|
/* read has completed synchronously*/
|
|
cfstore_flash_journal_callback(ret, FLASH_JOURNAL_OPCODE_LOG_BLOB);
|
|
ret = ctx->status;
|
|
}
|
|
/* wait for async completion handler*/
|
|
}
|
|
else
|
|
{
|
|
/* nothing to be logged so move back to ready state indicating success*/
|
|
cfstore_flash_journal_callback(ctx->expected_blob_size, FLASH_JOURNAL_OPCODE_LOG_BLOB);
|
|
}
|
|
out0:
|
|
return ret;
|
|
}
|
|
|
|
/* @brief fsm handler when in reading state */
|
|
static int32_t cfstore_fsm_logging(void* context)
|
|
{
|
|
cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered:ctx->status=%ld\n", __func__, ctx->status);
|
|
/* check the correct amount of data was written */
|
|
if(ctx->status < JOURNAL_STATUS_OK){
|
|
CFSTORE_ERRLOG("%s:Error: FlashJournal_log() failed (ret=%d)\n", __func__, (int) ctx->status);
|
|
/* move to ready state. cfstore client is expected to Uninitialize() before further calls */
|
|
cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
|
|
ctx->status = cfstore_flash_map_error(ctx->status);
|
|
}
|
|
else
|
|
{ /* ctx->status >= 0 (status == 0 when everything is deleted) */
|
|
if(ctx->status == (int32_t)ctx->expected_blob_size){
|
|
/* move to the committing state to commit to flash*/
|
|
ctx->status = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_committing, ctx);
|
|
} else {
|
|
CFSTORE_ERRLOG("%s:Error: FlashJournal_log() failed to log the expected number of bytes (ctx->expected_blob_size=%d, committed=%d)\n", __func__, (int) ctx->expected_blob_size, (int) ctx->status);
|
|
ctx->status = ARM_DRIVER_ERROR;
|
|
}
|
|
}
|
|
return ctx->status;
|
|
}
|
|
|
|
|
|
static int32_t cfstore_fsm_log_on_exit(void* context)
|
|
{
|
|
(void) context;
|
|
CFSTORE_FENTRYLOG("%s:entered:\n", __func__);
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
|
|
/* @brief fsm handler when entering committing state
|
|
* @note
|
|
* Its unnecessary to provide CS protection for the flashJouranl_commit() as the all the
|
|
* _log() operations affecting the commit have been performed, and no more _log() operations
|
|
* can happen until we're back in the ready state
|
|
*/
|
|
static int32_t cfstore_fsm_commit_on_entry(void* context)
|
|
{
|
|
int32_t ret = JOURNAL_STATUS_OK;
|
|
cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered:\n", __func__);
|
|
if(ctx->area_0_head && ctx->area_dirty_flag == true)
|
|
{
|
|
ret = FlashJournal_commit(&ctx->jrnl);
|
|
CFSTORE_TP(CFSTORE_TP_FSM, "%s:debug: FlashJournal_commit() (ret=%d)\n", __func__, (int) ret);
|
|
if(ret < JOURNAL_STATUS_OK){
|
|
CFSTORE_ERRLOG("%s:Error: FlashJournal_commit() failed (ret=%d)\n", __func__, (int) ret);
|
|
/* move to ready state. cfstore client is expected to Uninitialize() before further calls */
|
|
cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
|
|
} else if(ret > 0){
|
|
/* read has completed synchronously*/
|
|
cfstore_flash_journal_callback(ret, FLASH_JOURNAL_OPCODE_COMMIT);
|
|
ret = ctx->status;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* a commit should not be made because there have been no flashJournal_log() calls since the last commit.
|
|
* If a _commit() call was made without any _log() calls then it would result in the flash being erased
|
|
* because flash journal essentially contains a mirror image of the configuration store sram area, which
|
|
* has to be *** FULLY*** repopulated before each _commit(). */
|
|
cfstore_flash_journal_callback(ARM_DRIVER_OK_DONE, FLASH_JOURNAL_OPCODE_COMMIT);
|
|
ret = ctx->status;
|
|
}
|
|
/* wait for async callback */
|
|
CFSTORE_FENTRYLOG("%s:exiting: FlashJournal_commit() (ret=%d)\n", __func__, (int) ret);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* @brief fsm handler when in committing state
|
|
* @note
|
|
* Its unnecessary to provide CS protection for the flashJouranl_commit() as the all the
|
|
* _log() operations affecting the commit have been performed, and no more _log() operations
|
|
* can happen until we're back in the ready state
|
|
*/
|
|
static int32_t cfstore_fsm_committing(void* context)
|
|
{
|
|
cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
CFSTORE_ASSERT(ctx->fsm.state == cfstore_fsm_state_committing);
|
|
CFSTORE_ASSERT(ctx->cmd_code == FLASH_JOURNAL_OPCODE_COMMIT);
|
|
|
|
/* check the correct amount of data was written */
|
|
if(ctx->status < JOURNAL_STATUS_OK){
|
|
CFSTORE_ERRLOG("%s:Error: FlashJournal_commit() failed (ret=%d)\n", __func__, (int) ctx->status);
|
|
/* move to ready state. cfstore client is expected to Uninitialize() before further calls */
|
|
cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
|
|
ctx->status = cfstore_flash_map_error(ctx->status);
|
|
}
|
|
else if(ctx->status == JOURNAL_STATUS_OK)
|
|
{
|
|
ctx->status = cfstore_flash_map_error(ctx->status);
|
|
}
|
|
else
|
|
{ /* ctx->status > 0. for flash-journal-strategy-sequential version >0.4.0, commit() return no longer reports size of commit block */
|
|
ctx->status = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
|
|
}
|
|
return ctx->status;
|
|
}
|
|
|
|
static int32_t cfstore_fsm_commit_on_exit(void* context)
|
|
{
|
|
cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered:\n", __func__);
|
|
ctx->area_dirty_flag = false;
|
|
/* notify client of commit status */
|
|
cfstore_client_notify_data_init(&ctx->client_notify_data, CFSTORE_OPCODE_FLUSH, ctx->status, NULL);
|
|
ctx->client_callback_notify_flag = true;
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
/* int32_t cfstore_fsm_reset_on_entry(void* context){ (void) context;} */
|
|
/* int32_t cfstore_fsm_resetting(void* context){ (void) context;} */
|
|
/* int32_t cfstore_fsm_reset_on_exit(void* context){ (void) context;} */
|
|
|
|
static int32_t cfstore_fsm_ready_on_commit_req(void* context)
|
|
{
|
|
cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_logging, ctx);
|
|
}
|
|
|
|
/* int32_t cfstore_fsm_ready_on_entry(void* context){ (void) context;} */
|
|
/* int32_t cfstore_fsm_ready(void* context){ (void) context;} */
|
|
/* int32_t cfstore_fsm_ready_on_exit(void* context){ (void) context;} */
|
|
|
|
|
|
|
|
/* handler functions while in state */
|
|
static cfstore_fsm_handler cfstore_flash_fsm[cfstore_fsm_state_max][cfstore_fsm_event_max] =
|
|
{
|
|
/* state\event: init_done read_done log_done commit_req commit_done reset_done */
|
|
/* stopped */ {cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null },
|
|
/* init */ {cfstore_fsm_initing, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null },
|
|
/* reading */ {cfstore_fsm_null, cfstore_fsm_reading, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null },
|
|
/* logging */ {cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_logging, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null },
|
|
/* committing */ {cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_committing, cfstore_fsm_null },
|
|
/* resetting */ {cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null },
|
|
/* ready */ {cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_ready_on_commit_req, cfstore_fsm_null, cfstore_fsm_null },
|
|
};
|
|
|
|
/* handler functions for entering the state*/
|
|
cfstore_fsm_handler cfstore_fsm_on_entry[cfstore_fsm_state_max] =
|
|
{
|
|
cfstore_fsm_stop_on_entry,
|
|
cfstore_fsm_init_on_entry,
|
|
cfstore_fsm_read_on_entry,
|
|
cfstore_fsm_log_on_entry,
|
|
cfstore_fsm_commit_on_entry,
|
|
cfstore_fsm_null, /* cfstore_fsm_reset_on_entry */
|
|
cfstore_fsm_null /* cfstore_fsm_ready_on_entry */
|
|
};
|
|
|
|
/* handler functions for exiting state, currently none used */
|
|
cfstore_fsm_handler cfstore_fsm_on_exit[cfstore_fsm_state_max] =
|
|
{
|
|
cfstore_fsm_null, /* cfstore_fsm_stop_on_exit */
|
|
cfstore_fsm_null, /* cfstore_fsm_init_on_exit */
|
|
cfstore_fsm_read_on_exit,
|
|
cfstore_fsm_log_on_exit,
|
|
cfstore_fsm_commit_on_exit,
|
|
cfstore_fsm_null, /* cfstore_fsm_reset_on_exit */
|
|
cfstore_fsm_null /* cfstore_fsm_ready_on_exit */
|
|
};
|
|
|
|
|
|
/* @brief inject event into fsm */
|
|
static int32_t cfstore_fsm_state_handle_event(cfstore_fsm_t* fsm, cfstore_fsm_event_t event, void* context)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered: fsm=%p, fsm->state=%d, event=%d (%s), ctx=%p\n", __func__, fsm, fsm->state, event, cfstore_flash_event_str[event], ctx);
|
|
CFSTORE_ASSERT(event < cfstore_fsm_event_max);
|
|
fsm->event = event;
|
|
if(cfstore_flash_fsm[fsm->state][fsm->event] != NULL){
|
|
ret = cfstore_flash_fsm[fsm->state][fsm->event](ctx);
|
|
if(ret < ARM_DRIVER_OK){
|
|
#ifdef CFSTORE_DEBUG
|
|
CFSTORE_ERRLOG("%s:FSM:EVT:Error: cfstore_flash_fsm[%s][%s] failed\n", __func__, (char*) cfstore_flash_state_str[fsm->state], (char*) cfstore_flash_event_str[fsm->event]);
|
|
#endif
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
/* do not clear context data set by caller as it may be used later
|
|
* fsm->event = cfstore_fsm_event_max;
|
|
* ctx->status = 0;
|
|
* ctx->cmd_code = (FlashJournal_OpCode_t)((int) FLASH_JOURNAL_OPCODE_RESET+1);
|
|
*/
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* @brief get the current state of the fsm */
|
|
static cfstore_fsm_state_t cfstore_fsm_state_get(cfstore_fsm_t* fsm)
|
|
{
|
|
return fsm->state;
|
|
}
|
|
|
|
/* @brief function to move to new fsm state, calling state exit function for old state and entry function for new state */
|
|
static int32_t cfstore_fsm_state_set(cfstore_fsm_t* fsm, cfstore_fsm_state_t new_state, void* ctx)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
cfstore_ctx_t* context = (cfstore_ctx_t*) ctx;
|
|
#ifdef CFSTORE_DEBUG
|
|
cfstore_fsm_state_t old_state = fsm->state;
|
|
#endif
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered: fsm=%p, ctx=%p\n", __func__, fsm, ctx);
|
|
#ifdef CFSTORE_DEBUG
|
|
CFSTORE_TP(CFSTORE_TP_FSM, "%s:FSM:REQ RX: fsm->state=%d (%s): new_state=%d (%s)\n", __func__, (int) fsm->state, cfstore_flash_state_str[fsm->state], (int) new_state, cfstore_flash_state_str[new_state]);
|
|
#endif
|
|
CFSTORE_ASSERT(fsm != NULL);
|
|
CFSTORE_ASSERT(new_state < cfstore_fsm_state_max);
|
|
CFSTORE_ASSERT(ctx != NULL);
|
|
CFSTORE_ASSERT(fsm->state < cfstore_fsm_state_max);
|
|
|
|
if(cfstore_fsm_on_exit[fsm->state] != NULL){
|
|
ret = cfstore_fsm_on_exit[fsm->state](ctx);
|
|
if(ret < ARM_DRIVER_OK){
|
|
#ifdef CFSTORE_DEBUG
|
|
CFSTORE_ERRLOG("%s:FSM:REQ RX:%s:%s:Error: cfstore_fsm_on_exit() failed\n", __func__, cfstore_flash_state_str[fsm->state], cfstore_flash_state_str[new_state]);
|
|
#endif
|
|
/* handling of the error is done in the on_exit() method, which best knows how the state to move to */
|
|
return ret;
|
|
}
|
|
}
|
|
fsm->state = new_state;
|
|
if(cfstore_fsm_on_entry[new_state] != NULL){
|
|
ret = cfstore_fsm_on_entry[new_state](ctx);
|
|
if(ret < ARM_DRIVER_OK){
|
|
#ifdef CFSTORE_DEBUG
|
|
CFSTORE_TP(CFSTORE_TP_FSM, "%s:FSM:REQ RX: fsm->state=%d (%s): new_state=%d (%s): Error: cfstore_fsm_on_entry() failed (ret=%" PRId32 ")\n", __func__, (int) fsm->state, cfstore_flash_state_str[fsm->state], (int) new_state, cfstore_flash_state_str[new_state], ret);
|
|
#endif
|
|
/* handling of the error is done in the on_entry() method, which best knows how the state to move to */
|
|
return ret;
|
|
}
|
|
}
|
|
if(context->client_callback_notify_flag == true)
|
|
{
|
|
cfstore_client_notify_data_t notify_data;
|
|
|
|
CFSTORE_TP(CFSTORE_TP_FSM, "%s:doing client callback\n", __func__);
|
|
|
|
/* only one set of client notify data is required as there can only be 1 outstanding flash journal async notificaion
|
|
* at one time. */
|
|
context->client_callback_notify_flag = false; /* prevents re-calling callback if this function gets called again */
|
|
memcpy(¬ify_data, &context->client_notify_data, sizeof(cfstore_client_notify_data_t));
|
|
/* clear context state before initiating call */
|
|
cfstore_client_notify_data_init(&context->client_notify_data, CFSTORE_OPCODE_MAX, ARM_DRIVER_ERROR, NULL);
|
|
cfstore_ctx_client_notify(ctx, ¬ify_data);
|
|
}
|
|
CFSTORE_TP(CFSTORE_TP_FSM, "%s:FSM:REQ DONE: fsm->state=%d (%s): new_state=%d (%s)\n", __func__, (int) old_state, cfstore_flash_state_str[old_state], (int) new_state, cfstore_flash_state_str[new_state]);
|
|
return ret;
|
|
}
|
|
|
|
static bool cfstore_flash_journal_is_async_op_pending(cfstore_ctx_t* ctx)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered: fsm->state=%s\n", __func__, (char*) cfstore_flash_state_str[cfstore_fsm_state_get(&ctx->fsm)]);
|
|
if(cfstore_fsm_state_get(&ctx->fsm) != cfstore_fsm_state_ready)
|
|
{
|
|
/* flash journal async operation is in progress */
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static int32_t cfstore_flash_init(void)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered: \n", __func__);
|
|
CFSTORE_FENTRYLOG("%s:: CFSTORE_CONFIG_BACKEND_FLASH_ENABLED=%d\n", __func__, (int) CFSTORE_CONFIG_BACKEND_FLASH_ENABLED);
|
|
ctx->cmd_code = (FlashJournal_OpCode_t)((int) FLASH_JOURNAL_OPCODE_RESET+1);
|
|
ctx->expected_blob_size = 0;
|
|
ctx->fsm.event = cfstore_fsm_event_max;
|
|
ctx->fsm.state = cfstore_fsm_state_stopped;
|
|
memset(&ctx->info, 0, sizeof(ctx->info));
|
|
ret = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_initing, ctx);
|
|
if(ret < 0){
|
|
CFSTORE_DBGLOG("%s:Error: cfstore_fsm_state_set() failed\n", __func__);
|
|
return ret;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* @brief de-initialise the flash journal */
|
|
static int32_t cfstore_flash_deinit(void)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered: fsm->state=%s\n", __func__, (char*) cfstore_flash_state_str[cfstore_fsm_state_get(&ctx->fsm)]);
|
|
ret = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_stopped, ctx);
|
|
if(ret < 0){
|
|
CFSTORE_TP(CFSTORE_TP_INIT, "%s:Error: cfstore_fsm_state_set() failed\n", __func__);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
static int32_t cfstore_flash_reset(void)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
|
|
ret = FlashJournal_reset(&ctx->jrnl);
|
|
if(ret != JOURNAL_STATUS_OK){
|
|
CFSTORE_ERRLOG("%s:Error: failed to reset flash journal (ret=%" PRId32 ")\n", __func__, ret);
|
|
goto out0;
|
|
}
|
|
out0:
|
|
return ret;
|
|
}
|
|
*/
|
|
|
|
static int32_t cfstore_flash_flush(cfstore_ctx_t* ctx)
|
|
{
|
|
int32_t ret = ARM_DRIVER_OK;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
/* put the async completion code state variables into a known state */
|
|
ctx->status = ARM_DRIVER_OK;
|
|
ctx->cmd_code = (FlashJournal_OpCode_t)((int) FLASH_JOURNAL_OPCODE_RESET+1);
|
|
|
|
/* cfstore_fsm_state_handle_event() is called at intr context via
|
|
* cfstore_flash_journal_callback(), and hence calls from app context are
|
|
* protected with CSs */
|
|
cfstore_critical_section_lock(&ctx->rw_area0_lock, __func__);
|
|
ret = cfstore_fsm_state_handle_event(&ctx->fsm, cfstore_fsm_event_commit_req, (void*) ctx);
|
|
cfstore_critical_section_unlock(&ctx->rw_area0_lock, __func__);
|
|
return ret;
|
|
}
|
|
|
|
#else /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
|
|
|
|
static bool cfstore_flash_journal_is_async_op_pending(cfstore_ctx_t* ctx) { CFSTORE_FENTRYLOG("%s:SRAM:entered:\n", __func__); (void) ctx; return false; }
|
|
|
|
/* @brief generate the CFSTORE_OPCODE_INITIALIZE callback notification */
|
|
static int32_t cfstore_flash_init(void)
|
|
{
|
|
cfstore_client_notify_data_t notify_data;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
|
|
CFSTORE_FENTRYLOG("%s:SRAM:entered:\n", __func__);
|
|
cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_INITIALIZE, ARM_DRIVER_OK, NULL);
|
|
cfstore_ctx_client_notify(ctx, ¬ify_data);
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
static int32_t cfstore_flash_deinit(void){ CFSTORE_FENTRYLOG("%s:SRAM:entered:\n", __func__); return ARM_DRIVER_OK; }
|
|
/* static int32_t cfstore_flash_reset(void) { CFSTORE_FENTRYLOG("%s:SRAM:entered:\n", __func__); return ARM_DRIVER_OK; }*/
|
|
static int32_t cfstore_flash_flush(cfstore_ctx_t* ctx)
|
|
{
|
|
cfstore_client_notify_data_t notify_data;
|
|
|
|
CFSTORE_FENTRYLOG("%s:SRAM:entered:\n", __func__);
|
|
cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_FLUSH, ARM_DRIVER_OK, NULL);
|
|
cfstore_ctx_client_notify(ctx, ¬ify_data);
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
|
|
|
|
/** @brief internal delete helper function.
|
|
* @note must be called within critical section.
|
|
*/
|
|
static int32_t cfstore_delete_ex(cfstore_area_hkvt_t* hkvt)
|
|
{
|
|
uint8_t* ptr = NULL;
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
ARM_CFSTORE_SIZE kv_size = 0;
|
|
ARM_CFSTORE_SIZE area_size = 0;
|
|
ARM_CFSTORE_SIZE realloc_size = 0; /* size aligned to flash program_unit size */
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
cfstore_file_t* file;
|
|
cfstore_list_node_t* node;
|
|
cfstore_list_node_t* file_list = &ctx->file_list;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered:(ctx->area_0_head=%p, ctx->area_0_tail=%p)\n", __func__, ctx->area_0_head, ctx->area_0_tail);
|
|
kv_size = cfstore_hkvt_get_size(hkvt);
|
|
area_size = cfstore_ctx_get_area_len();
|
|
memmove(hkvt->head, hkvt->tail, ctx->area_0_tail - hkvt->tail);
|
|
/* zero the deleted KV memory */
|
|
memset(ctx->area_0_tail-kv_size, 0, kv_size);
|
|
|
|
/* In the general case the new ((area_size - kv_size) % program_unit > 0). The new area_size is
|
|
* aligned to a program_unit boundary to facilitate r/w to flash and so the memory realloc size
|
|
* is calculated to align, as follows */
|
|
/* setup the reallocation memory size. */
|
|
realloc_size = area_size - kv_size;
|
|
if(realloc_size % cfstore_ctx_get_program_unit(ctx) > 0){
|
|
realloc_size += (cfstore_ctx_get_program_unit(ctx) - (realloc_size % cfstore_ctx_get_program_unit(ctx)));
|
|
}
|
|
/* realloc() can return non-zero ptr for size = 0 when the last KV is deleted */
|
|
if(realloc_size > 0)
|
|
{
|
|
ptr = (uint8_t*) CFSTORE_REALLOC((void*) ctx->area_0_head, realloc_size);
|
|
/* realloc can return NULL when the last KV is deleted.
|
|
* It also appears that realloc can return non-zero ptr even when realloc_size = 0 */
|
|
if(ptr == NULL){
|
|
CFSTORE_ERRLOG("%s:Error:realloc failed\n", __func__);
|
|
cfstore_ctx_reset(ctx);
|
|
return ARM_CFSTORE_DRIVER_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
/* check realloc() hasnt move area in memory from cfstore_ctx_g.area_0_head */
|
|
if(ptr != ctx->area_0_head){
|
|
CFSTORE_TP(CFSTORE_TP_DELETE, "%s: cfstore_ctx_g.area_0_head pointer changed (cfstore_ctx_g.area_0_head=%p, cfstore_ctx_g.area_0_tail=%p)\n", __func__, ctx->area_0_head, ptr);
|
|
/* realloc() has moved the area in memory */
|
|
ctx->area_0_head = ptr;
|
|
}
|
|
/* set tail to be the end of the new area, which will be updated by cfstore_flash_set_tail */
|
|
ctx->area_0_tail = ptr + area_size - kv_size;
|
|
ret = cfstore_flash_set_tail();
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: cfstore_flash_set_tail() failed (ret=%" PRId32 ")\n", __func__, ret);
|
|
goto out0;
|
|
}
|
|
|
|
/* now have to walk the file list updating head pointers for the KVs that remain*/
|
|
node = file_list->next;
|
|
while(node != file_list){
|
|
/* Any KV positioned later in the area than the deleted KV will require file head pointers updating.
|
|
* If file's head pointer is beyond the deleted KV tail then the file->head needs to be updated
|
|
* to reflect the memove */
|
|
file = (cfstore_file_t*) node;
|
|
if(file->head >= hkvt->head){
|
|
file->head -= kv_size;
|
|
}
|
|
node = node->next;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* realloc_size = 0 */
|
|
CFSTORE_FREE((void*) ctx->area_0_head);
|
|
ctx->area_0_head = NULL;
|
|
ctx->area_0_tail = NULL;
|
|
}
|
|
ret = ARM_DRIVER_OK;
|
|
out0:
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* File operations
|
|
*/
|
|
|
|
static cfstore_file_t* cfstore_file_get(ARM_CFSTORE_HANDLE hkey)
|
|
{
|
|
return (cfstore_file_t*) hkey;
|
|
}
|
|
|
|
static cfstore_file_t* cfstore_file_create(cfstore_area_hkvt_t* hkvt, ARM_CFSTORE_FMODE flags, ARM_CFSTORE_HANDLE hkey, cfstore_list_node_t *list_head)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
cfstore_file_t* file = (cfstore_file_t*) hkey;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
if(file != NULL){
|
|
memset(file, 0, sizeof(cfstore_file_t));
|
|
CFSTORE_INIT_LIST_HEAD(&file->node);
|
|
ret = cfstore_hkvt_refcount_inc(hkvt, NULL);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: cfstore_hkvt_refcount_inc() failed (ret=%" PRId32 ")\n", __func__, ret);
|
|
return NULL;
|
|
}
|
|
file->head = hkvt->head;
|
|
file->flags.read = flags.read;
|
|
file->flags.write = flags.write;
|
|
if(list_head != NULL){
|
|
cfstore_listAdd(list_head, &file->node, list_head);
|
|
}
|
|
}
|
|
return file;
|
|
}
|
|
|
|
/* @brief required to be in critical section when called. */
|
|
static int32_t cfstore_file_destroy(cfstore_file_t* file)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
cfstore_area_hkvt_t hkvt;
|
|
uint8_t refcount = 0;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
if(file) {
|
|
hkvt = cfstore_get_hkvt_from_head_ptr(file->head);
|
|
CFSTORE_ASSERT(cfstore_hkvt_is_valid(&hkvt, cfstore_ctx_get()->area_0_tail) == true);
|
|
ret = ARM_DRIVER_OK;
|
|
cfstore_hkvt_refcount_dec(&hkvt, &refcount);
|
|
CFSTORE_TP(CFSTORE_TP_FILE, "%s:refcount =%d\n", __func__, (int)refcount);
|
|
if(refcount == 0){
|
|
/* check for delete */
|
|
CFSTORE_TP(CFSTORE_TP_FILE, "%s:checking delete flag\n", __func__);
|
|
if(cfstore_hkvt_get_flags_delete(&hkvt)){
|
|
ret = cfstore_delete_ex(&hkvt);
|
|
}
|
|
/* reset client buffer to empty ready for reuse */
|
|
/* delete the file even if not deleting the KV*/
|
|
cfstore_listDel(&file->node);
|
|
memset(file, 0, sizeof(cfstore_file_t));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief check whether this is an valid buffer
|
|
*
|
|
* @param hkey
|
|
* IN: The key handle to be validated
|
|
*
|
|
* ctx
|
|
* IN: cfstore context block
|
|
*/
|
|
static bool cfstore_file_is_valid(ARM_CFSTORE_HANDLE hkey, cfstore_ctx_t* ctx)
|
|
{
|
|
cfstore_file_t* file = cfstore_file_get(hkey);
|
|
|
|
if(ctx->area_0_head != NULL && ctx->area_0_tail != NULL){
|
|
if(file->head < ctx->area_0_head || file->head > ctx->area_0_tail){
|
|
return 0;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @brief check whether this is an empty buffer, or whether it
|
|
* has valid data
|
|
*
|
|
* @param hkey
|
|
* IN: The key handle to be validated
|
|
*
|
|
* ctx
|
|
* IN: cfstore context block
|
|
*/
|
|
static bool cfstore_file_is_empty(ARM_CFSTORE_HANDLE hkey)
|
|
{
|
|
ARM_CFSTORE_HANDLE_INIT(zero);
|
|
if(hkey != NULL){
|
|
return !memcmp(hkey, zero, CFSTORE_HANDLE_BUFSIZE);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* @brief See definition in configuration_store.h for description. */
|
|
ARM_CFSTORE_CAPABILITIES cfstore_get_capabilities(void)
|
|
{
|
|
/* getting capabilities doesnt change the sram area so this can happen independently of
|
|
* an oustanding async operation. its unnecessary to check the fsm state */
|
|
return cfstore_caps_g;
|
|
}
|
|
|
|
|
|
/* @brief check the flags argument are supported */
|
|
static int32_t cfstore_validate_fmode_flags(ARM_CFSTORE_FMODE flags)
|
|
{
|
|
if(flags.continuous){
|
|
CFSTORE_ERRLOG("%s:Error:Continuous flag not supported.\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
|
|
}
|
|
if(flags.lazy_flush){
|
|
CFSTORE_ERRLOG("%s:Error:Lazy flush flag not supported.\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
|
|
}
|
|
if(flags.flush_on_close){
|
|
CFSTORE_ERRLOG("%s:Error:Flush on close flag not supported.\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
|
|
}
|
|
if(flags.storage_detect){
|
|
CFSTORE_ERRLOG("%s:Error:Storage detect flag not supported.\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
|
|
}
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
|
|
/* @brief validate the client supplied opaque handle */
|
|
static CFSTORE_INLINE int32_t cfstore_validate_handle(ARM_CFSTORE_HANDLE hkey)
|
|
{
|
|
if(hkey == NULL){
|
|
return ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE;
|
|
}
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
/* @brief check the flash security features are valid (internal use only) */
|
|
static int32_t cfstore_validate_flash_security_features(const ARM_STORAGE_SECURITY_FEATURES *security)
|
|
{
|
|
CFSTORE_ASSERT(security != NULL);
|
|
|
|
if(security->acls){
|
|
CFSTORE_ERRLOG("%s:Error: flash security features acls flag not supported.\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
|
|
}
|
|
if(security->internal_flash){
|
|
CFSTORE_ERRLOG("%s:Error: flash security features internal_flash flag not supported.\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
|
|
}
|
|
if(security->rollback_protection){
|
|
CFSTORE_ERRLOG("%s:Error: flash security features rollback_protection flag not supported.\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
|
|
}
|
|
if(security->tamper_proof){
|
|
CFSTORE_ERRLOG("%s:Error: flash security features tamper_proof flag not supported.\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
|
|
}
|
|
if(security->board_level_attacks){
|
|
CFSTORE_ERRLOG("%s:Error: flash security features board level attacks flag not supported.\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
|
|
}
|
|
if(security->software_attacks){
|
|
CFSTORE_ERRLOG("%s:Error: flash security features device_software flag not supported.\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
|
|
}
|
|
if(security->chip_level_attacks){
|
|
CFSTORE_ERRLOG("%s:Error: flash security features chip level attacks flag not supported.\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
|
|
}
|
|
if(security->side_channel_attacks){
|
|
CFSTORE_ERRLOG("%s:Error: flash security features side channel attacks flag not supported.\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
|
|
}
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
/* @brief check the key descriptor are valid (internal use only) */
|
|
static int32_t cfstore_validate_flash_data_retention_level(const uint8_t drl)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
|
|
switch(drl)
|
|
{
|
|
case ARM_RETENTION_WHILE_DEVICE_ACTIVE :
|
|
case ARM_RETENTION_ACROSS_SLEEP :
|
|
case ARM_RETENTION_ACROSS_DEEP_SLEEP :
|
|
case ARM_RETENTION_BATTERY_BACKED :
|
|
case ARM_RETENTION_NVM :
|
|
ret = ARM_DRIVER_OK;
|
|
break;
|
|
default:
|
|
CFSTORE_ERRLOG("%s:Error: data retention level (%d) not supported.\n", __func__, drl);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
|
|
break;
|
|
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* @brief check the access control list is valid (internal use only) */
|
|
static int32_t cfstore_validate_access_control_list(const ARM_CFSTORE_ACCESS_CONTROL_LIST acl)
|
|
{
|
|
if(acl.perm_owner_execute)
|
|
{
|
|
CFSTORE_ERRLOG("%s:Error: Access control list with permission owner execute set is not supported.\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
|
|
}
|
|
if(acl.perm_other_execute)
|
|
{
|
|
CFSTORE_ERRLOG("%s:Error: Access control list with permission other execute set is not supported.\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
|
|
}
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
/* @brief check the key descriptor is valid */
|
|
static int32_t cfstore_validate_key_desc(const ARM_CFSTORE_KEYDESC *kdesc)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
|
|
if(kdesc == NULL){
|
|
return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_DESCRIPTOR;
|
|
}
|
|
ret = cfstore_validate_access_control_list(kdesc->acl);
|
|
if(ret < ARM_DRIVER_OK){
|
|
return ret;
|
|
}
|
|
ret = cfstore_validate_flash_data_retention_level(kdesc->drl);
|
|
if(ret < ARM_DRIVER_OK){
|
|
return ret;
|
|
}
|
|
ret = cfstore_validate_flash_security_features(&kdesc->security);
|
|
if(ret < ARM_DRIVER_OK){
|
|
return ret;
|
|
}
|
|
ret = cfstore_validate_fmode_flags(kdesc->flags);
|
|
if(ret < ARM_DRIVER_OK){
|
|
return ret;
|
|
}
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief check the key_len pointer is valid
|
|
*
|
|
* @param hkey
|
|
* IN: The key handle to be validated
|
|
*/
|
|
static CFSTORE_INLINE int32_t cfstore_validate_len_ptr(ARM_CFSTORE_SIZE *len)
|
|
{
|
|
if(len == NULL){
|
|
return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_LEN;
|
|
}
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
/* @brief return a pointer to the next { or }, or NULL if not present */
|
|
static inline char* cfstore_validate_pos_next_brace(const char* pos)
|
|
{
|
|
char* pos_open = strchr(pos, '{');
|
|
char* pos_close = strchr(pos, '}');
|
|
if(pos_open != NULL) {
|
|
if(pos_close != NULL){
|
|
return pos_open < pos_close ? pos_open : pos_close;
|
|
}
|
|
return pos_open;
|
|
}
|
|
return pos_close;
|
|
}
|
|
|
|
|
|
static int32_t cfstore_validate_key_name_ex(const char* key_name, const char* permissible)
|
|
{
|
|
char* pos = NULL;
|
|
int brace_count = 0;
|
|
ARM_CFSTORE_SIZE len = 0;
|
|
ARM_CFSTORE_SIZE valid_len = 0;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
if(key_name != NULL){
|
|
/* check the key_name is terminated by a 0 */
|
|
pos = (char*) memchr(key_name, '\0', CFSTORE_KEY_NAME_MAX_LENGTH+1);
|
|
if(pos == NULL){
|
|
CFSTORE_ERRLOG("%s:key_name does not have terminating null.\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME;
|
|
}
|
|
/* check for zero length key_name*/
|
|
if(strlen(key_name) == 0){
|
|
CFSTORE_ERRLOG("%s:Error: invalid key_name.\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME;
|
|
}
|
|
/* check the key_name len is less than the max length (220) */
|
|
len = strlen(key_name);
|
|
if(len > CFSTORE_KEY_NAME_MAX_LENGTH){
|
|
CFSTORE_ERRLOG("%s:key_name string is longer (%d) than the supported maximum (%d).\n", __func__, (int) len, (int) CFSTORE_KEY_NAME_MAX_LENGTH);
|
|
return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME;
|
|
}
|
|
/* check the key_name only contains permissible characters */
|
|
valid_len = strspn(key_name, permissible);
|
|
if(valid_len != len){
|
|
CFSTORE_ERRLOG("%s:Invalid character (%c) found in key_name (key_name=%s).\n", __func__, key_name[valid_len], key_name);
|
|
return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME;
|
|
}
|
|
|
|
/*check there isnt a leading '.' on the kv name */
|
|
if(key_name[0] == '.'){
|
|
CFSTORE_ERRLOG("%s:Leading (.) character found in key_name (key_name=%s) is not allowed.\n", __func__, key_name);
|
|
return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME;
|
|
}
|
|
|
|
/* - check for matching '{' for each '}' present
|
|
* - only check a string if either { or } are present
|
|
* i.e. dont process string without
|
|
* checking for existence of single brace, and checking for either { or } so
|
|
* that the case where } is the first brace is convered.
|
|
* - start loop at first { or } char, both {} covers case where } is the first brace
|
|
* - (brace_count >=0 && brace_count <= 1) must always be true
|
|
* - brace_count must == 0 at end of string
|
|
*/
|
|
pos = cfstore_validate_pos_next_brace(key_name);
|
|
while(pos != NULL && brace_count >= 0 && brace_count <= 1)
|
|
{
|
|
switch(*pos)
|
|
{
|
|
case '{':
|
|
brace_count++;
|
|
break;
|
|
case '}':
|
|
brace_count--;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
pos++;
|
|
pos = cfstore_validate_pos_next_brace(pos);
|
|
}
|
|
if(brace_count != 0){
|
|
CFSTORE_ERRLOG("%s: Unmatched brace found in key_name (count=%" PRId32 ".\n", __func__, brace_count);
|
|
return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME;
|
|
}
|
|
}
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
|
|
/* @brief check the key name is valid */
|
|
static int32_t cfstore_validate_key_name(const char* key_name)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
|
|
ret = cfstore_uvisor_security_context_prefix_check(key_name);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: failed uvisor security context check.\n", __func__);
|
|
return ret;
|
|
}
|
|
return cfstore_validate_key_name_ex(key_name, CFSTORE_KEY_NAME_CHARS_ACCEPTABLE);
|
|
}
|
|
|
|
/* @brief check the key name query is valid */
|
|
static int32_t cfstore_validate_key_name_query(const char* key_name_query)
|
|
{
|
|
return cfstore_validate_key_name_ex(key_name_query, CFSTORE_KEY_NAME_QUERY_CHARS_ACCEPTABLE);
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief check the value length field is valid
|
|
*
|
|
* @param key_name
|
|
* IN: The key name string to be validated
|
|
* @note This will be replaced with the actual uvisor call, when available.
|
|
*/
|
|
static CFSTORE_INLINE int32_t cfstore_validate_value_len(ARM_CFSTORE_SIZE value_len)
|
|
{
|
|
if(value_len <= CFSTORE_VALUE_SIZE_MAX) {
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
return ARM_CFSTORE_DRIVER_ERROR_VALUE_SIZE_TOO_LARGE;
|
|
}
|
|
|
|
|
|
/* @brief See definition in configuration_store.h for description. */
|
|
static int32_t cfstore_get_key_name_ex(cfstore_area_hkvt_t *hkvt, char* key_name, uint8_t *key_name_len)
|
|
{
|
|
int32_t ret = ARM_DRIVER_OK;
|
|
int32_t max_len = 0;
|
|
|
|
max_len = cfstore_hkvt_get_key_len(hkvt) + 1;
|
|
max_len = max_len <= *key_name_len ? max_len : *key_name_len;
|
|
memcpy(key_name, (const char*) hkvt->key, max_len-1);
|
|
key_name[max_len-1] = '\0';
|
|
*key_name_len = max_len;
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* @brief See definition in configuration_store.h for description. */
|
|
static int32_t cfstore_get_key_name(ARM_CFSTORE_HANDLE hkey, char* key_name, uint8_t *key_name_len)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
cfstore_area_hkvt_t hkvt;
|
|
cfstore_client_notify_data_t notify_data;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
|
|
CFSTORE_ASSERT(key_name != NULL);
|
|
CFSTORE_ASSERT(key_name_len != NULL);
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
if(!cfstore_ctx_is_initialised(ctx)) {
|
|
CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
|
|
goto out0;
|
|
}
|
|
/* getting a keyname doesnt change the sram area so this can happen independently of
|
|
* an oustanding async operation. its unnecessary to check the fsm state */
|
|
ret = cfstore_validate_handle(hkey);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__);
|
|
goto out0;
|
|
}
|
|
if(key_name == NULL){
|
|
CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME;
|
|
goto out0;
|
|
}
|
|
ret = cfstore_validate_len_ptr((ARM_CFSTORE_SIZE*)key_name_len);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: invalid key_name_len argument.\n", __func__);
|
|
goto out0;
|
|
}
|
|
memset(&hkvt, 0, sizeof(hkvt));
|
|
hkvt = cfstore_get_hkvt(hkey);
|
|
if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){
|
|
CFSTORE_ERRLOG("%s:ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE;
|
|
goto out0;
|
|
}
|
|
ret = cfstore_get_key_name_ex(&hkvt, key_name, key_name_len);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: cfstore_get_key_name_ex() returned error.\n", __func__);
|
|
goto out0;
|
|
}
|
|
ret = *key_name_len;
|
|
out0:
|
|
/* GetKeyName() always completes synchronously irrespective of flash mode, so indicate to caller */
|
|
cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_GET_KEY_NAME, ret, hkey);
|
|
cfstore_ctx_client_notify(ctx, ¬ify_data);
|
|
return ret;
|
|
}
|
|
|
|
/* @brief See definition in configuration_store.h for description. */
|
|
static ARM_CFSTORE_STATUS cfstore_get_status(void)
|
|
{
|
|
ARM_CFSTORE_STATUS status;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
|
|
memset(&status, 0, sizeof(status));
|
|
if(!cfstore_ctx_is_initialised(ctx)) {
|
|
CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
|
|
status.error = true;
|
|
}
|
|
/* getting status doesnt change the sram area so this can happen independently of
|
|
* an oustanding async operation. */
|
|
if(cfstore_flash_journal_is_async_op_pending(ctx))
|
|
{
|
|
status.in_progress = true;
|
|
}
|
|
else
|
|
{
|
|
status.in_progress = false;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/* @brief See definition in configuration_store.h for description. */
|
|
static int32_t cfstore_get_value_len(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_SIZE *value_len)
|
|
{
|
|
int32_t ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
|
|
cfstore_area_hkvt_t hkvt;
|
|
cfstore_client_notify_data_t notify_data;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
CFSTORE_ASSERT(hkey != NULL);
|
|
CFSTORE_ASSERT(value_len != NULL);
|
|
|
|
if(!cfstore_ctx_is_initialised(ctx)) {
|
|
CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
|
|
goto out0;
|
|
}
|
|
/* getting a value len doesnt change the sram area so this can happen independently of
|
|
* an oustanding async operation. its unnecessary to check the fsm state */
|
|
ret = cfstore_validate_handle(hkey);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__);
|
|
goto out0;
|
|
}
|
|
ret = cfstore_validate_len_ptr(value_len);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: invalid value len argument.\n", __func__);
|
|
goto out0;
|
|
}
|
|
hkvt = cfstore_get_hkvt(hkey);
|
|
if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){
|
|
CFSTORE_ERRLOG("%s:ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE;
|
|
goto out0;
|
|
}
|
|
*value_len = cfstore_hkvt_get_value_len(&hkvt);
|
|
ret = (int32_t) *value_len;
|
|
out0:
|
|
/* GetValueLen() always completes synchronously irrespective of flash mode, so indicate to caller */
|
|
cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_GET_VALUE_LEN, ret, hkey);
|
|
cfstore_ctx_client_notify(ctx, ¬ify_data);
|
|
return ret;
|
|
}
|
|
|
|
#ifdef CFSTORE_DEBUG
|
|
|
|
/* @brief debug trace a struct cfstore_area_hkvt_t, providing values for key field. */
|
|
static CFSTORE_INLINE void cfstore_hkvt_dump(cfstore_area_hkvt_t* hkvt, const char* tag)
|
|
{
|
|
/* #define noSymbol */
|
|
#ifdef noSymbol
|
|
char kname[CFSTORE_KEY_NAME_MAX_LENGTH+1];
|
|
char value[CFSTORE_KEY_NAME_MAX_LENGTH+1];
|
|
uint32_t klen = 0;
|
|
uint32_t vlen = 0;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
|
|
memset(kname, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1);
|
|
memset(value, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1);
|
|
klen = cfstore_hkvt_get_key_len(hkvt);
|
|
vlen = cfstore_hkvt_get_value_len(hkvt);
|
|
memcpy((void*)kname, (void*) hkvt->key, klen);
|
|
memcpy((void*)value, (void*) hkvt->value, vlen);
|
|
kname[klen] = '\0';
|
|
value[vlen] = '\0';
|
|
|
|
/* table column description
|
|
* col 1: tag, descriptive string supplied by client to identify context of table dump
|
|
* col 2: hkvt struct member that is to be reported i.e. head, key, value, tail
|
|
* col 3: the value of the pointer described in col 2.
|
|
* col 4: the value of the pointer described in col 3 as an offset from the start of the sram area
|
|
* col 5: field specified data e.g. for header, the extracted key length, value_length.
|
|
*/
|
|
CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:hkvt->head:%8p:%8p:klen=%08d:vlen=%08d:\n", tag, hkvt->head, (void*)(hkvt->head - ctx->area_0_head), (int) klen, (int) vlen);
|
|
CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:hkvt->key :%8p:%8p:%s\n", tag, hkvt->key, (void*)(hkvt->key - ctx->area_0_head), kname);
|
|
CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:hkvt->val :%8p:%8p:%s\n", tag, hkvt->value, (void*)(hkvt->value - ctx->area_0_head), value);
|
|
CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:hkvt->tail:%8p:%8p:\n", tag, hkvt->tail, (void*)(hkvt->tail - ctx->area_0_head));
|
|
return;
|
|
#else
|
|
(void) hkvt;
|
|
(void) tag;
|
|
|
|
#endif /* noSymbol */
|
|
}
|
|
|
|
static CFSTORE_INLINE void cfstore_flags_dump(ARM_CFSTORE_FMODE flag, const char* tag)
|
|
{
|
|
int pos = 0;
|
|
char flags[9];
|
|
|
|
pos += snprintf(&flags[pos], 9, "%c", flag.continuous ? 'C' : 'c');
|
|
pos += snprintf(&flags[pos], 9, "%c", flag.lazy_flush ? 'L' : 'l');
|
|
pos += snprintf(&flags[pos], 9, "%c", flag.flush_on_close ? 'F' : 'f');
|
|
pos += snprintf(&flags[pos], 9, "%c", flag.read ? 'R' : 'r');
|
|
pos += snprintf(&flags[pos], 9, "%c", flag.write ? 'W' : 'w');
|
|
pos += snprintf(&flags[pos], 9, "%c", flag.storage_detect ? 'S' : 's');
|
|
pos += snprintf(&flags[pos], 9, "--");
|
|
|
|
CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:flags :%s:(C=>continuous set, L=>lazy flush, F=>flush on close, R=>read, W=>write, S=>storage detect)\n", tag, flags);
|
|
return;
|
|
}
|
|
|
|
static CFSTORE_INLINE void cfstore_file_dump(cfstore_file_t* file, const char* tag)
|
|
{
|
|
#ifdef noSymbol
|
|
cfstore_area_hkvt_t hkvt;
|
|
|
|
CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:*** Dumping File Contents : Start ***\n", tag);
|
|
CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:file==hkey:%p\n", tag, file);
|
|
CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:rloc/wloc :%08u/%08u:\n", tag, (unsigned int) file->rlocation, (unsigned int) file->wlocation);
|
|
cfstore_flags_dump(file->flags, tag);
|
|
hkvt = cfstore_get_hkvt((ARM_CFSTORE_HANDLE)file);
|
|
cfstore_hkvt_dump(&hkvt, tag);
|
|
CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:*** Dumping File Contents : End ***\n", tag);
|
|
return;
|
|
#else
|
|
(void) file;
|
|
(void) tag;
|
|
|
|
#endif /* noSymbol */
|
|
}
|
|
|
|
/* dump sram contents of cfstore in a useful manner for debugging */
|
|
static CFSTORE_INLINE void cfstore_dump_contents(const char* tag)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
cfstore_area_hkvt_t hkvt;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
|
|
CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:*** Dumping CFSTORE Contents : Start ***\n", tag);
|
|
CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:cfstore_ctx_g.area_0_head=%8p\n", tag, ctx->area_0_head);
|
|
CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:cfstore_ctx_g.area_0_tail=%8p\n", tag, ctx->area_0_tail);
|
|
ret = cfstore_get_head_hkvt(&hkvt);
|
|
if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND){
|
|
CFSTORE_TP(CFSTORE_TP_VERBOSE1, "%s:CFSTORE has no KVs\n", tag);
|
|
goto out0;
|
|
} else if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: could not get head of list.\n", tag);
|
|
goto out0;
|
|
}
|
|
while(cfstore_get_next_hkvt(&hkvt, &hkvt) != ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND)
|
|
{
|
|
cfstore_hkvt_dump(&hkvt, tag);
|
|
}
|
|
out0:
|
|
CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:*** Dumping CFSTORE Contents : End ***\n", tag);
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
static CFSTORE_INLINE void cfstore_hkvt_dump(cfstore_area_hkvt_t* hkvt, const char* tag){ (void) hkvt; (void) tag; return; }
|
|
static CFSTORE_INLINE void cfstore_file_dump(cfstore_file_t* file, const char* tag){ (void) file; (void) tag; return; }
|
|
static CFSTORE_INLINE void cfstore_dump_contents(const char* tag){ (void) tag; return; }
|
|
static CFSTORE_INLINE void cfstore_flags_dump(ARM_CFSTORE_FMODE flag, const char* tag){ (void) flag; (void) tag; return; }
|
|
#endif /*CFSTORE_DEBUG*/
|
|
|
|
/*
|
|
* CS operations
|
|
*/
|
|
|
|
/* @brief See definition in configuration_store.h for description. */
|
|
ARM_DRIVER_VERSION cfstore_get_version(void)
|
|
{
|
|
/* getting version info doesnt change the sram area so this can happen independently of
|
|
* an oustanding async operation. its unnecessary to check the fsm state */
|
|
return cfstore_driver_version_g;
|
|
}
|
|
|
|
|
|
/*
|
|
* CS API Key-Value operations
|
|
*/
|
|
|
|
/* @brief See definition in configuration_store.h for description. */
|
|
static int32_t cfstore_delete(ARM_CFSTORE_HANDLE hkey)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
cfstore_area_hkvt_t hkvt;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
cfstore_client_notify_data_t notify_data;
|
|
|
|
CFSTORE_TP((CFSTORE_TP_DELETE|CFSTORE_TP_FENTRY), "%s:entered\n", __func__);
|
|
if(!cfstore_ctx_is_initialised(ctx)) {
|
|
CFSTORE_TP(CFSTORE_TP_DELETE, "%s:Error: CFSTORE is not initialised.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
|
|
goto out0;
|
|
}
|
|
/* deleting a key will change the sram area while a logging/flushing operation is pending, which
|
|
* should not happen while an async operation is outstanding */
|
|
if(cfstore_flash_journal_is_async_op_pending(ctx)) {
|
|
CFSTORE_TP(CFSTORE_TP_DELETE, "%s:Debug: flash journal operation pending (awaiting asynchronous notification).\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING;
|
|
goto out0;
|
|
}
|
|
ret = cfstore_validate_handle(hkey);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__);
|
|
goto out0;
|
|
}
|
|
if(!cfstore_is_kv_client_deletable((cfstore_file_t*) hkey)){
|
|
CFSTORE_ERRLOG("%s:Error: client is not permitted to delete KV.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_NO_PERMISSIONS;
|
|
goto out0;
|
|
}
|
|
hkvt = cfstore_get_hkvt(hkey);
|
|
/* check its a valid hkvt */
|
|
if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){
|
|
CFSTORE_ERRLOG("%s:ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE;
|
|
goto out0;
|
|
}
|
|
/* set the delete flag so the delete occurs when the file is closed
|
|
* no further handles will be returned to this key */
|
|
cfstore_hkvt_set_flags_delete(&hkvt, true);
|
|
out0:
|
|
/* Delete() always completes synchronously irrespective of flash mode, so indicate to caller */
|
|
cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_DELETE, ret, NULL);
|
|
cfstore_ctx_client_notify(ctx, ¬ify_data);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/** @brief Internal find function using hkvt's.
|
|
*
|
|
* @note
|
|
* Not the following:
|
|
* - Any required locks should be taken before this function is called.
|
|
* This function does not affect refcount for underlying KVs.
|
|
* - The function assumes the arguments have been validated before calling this function
|
|
* - No acl policy is enforced by the function.
|
|
*
|
|
* @return return_value
|
|
* On success (finding a KV matching the query) ARM_DRIVER_OK is
|
|
* returned. If a KV is not found matching the description then
|
|
* ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND is returned.
|
|
*/
|
|
static int32_t cfstore_find_ex(const char* key_name_query, cfstore_area_hkvt_t *prev, cfstore_area_hkvt_t *next)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
uint8_t next_key_len;
|
|
char key_name[CFSTORE_KEY_NAME_MAX_LENGTH+1];
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
|
|
CFSTORE_TP((CFSTORE_TP_FIND|CFSTORE_TP_FENTRY), "%s:entered: key_name_query=\"%s\", prev=%p, next=%p\n", __func__, key_name_query, prev, next);
|
|
if(prev == NULL){
|
|
ret = cfstore_get_head_hkvt(next);
|
|
/* CFSTORE_TP(CFSTORE_TP_FIND, "%s:next->head=%p, next->key=%p, next->value=%p, next->tail=%p, \n", __func__, next->head, next->key, next->value, next->tail); */
|
|
if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND){
|
|
CFSTORE_TP(CFSTORE_TP_FIND, "%s:CFSTORE has no KVs\n", __func__);
|
|
return ret;
|
|
} else if(ret < ARM_DRIVER_OK) {
|
|
CFSTORE_TP(CFSTORE_TP_FIND, "%s:failed to find the first KV in area\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
/* check for no KVs in the store => hkvt is not valid */
|
|
if(!cfstore_hkvt_is_valid(next, ctx->area_0_tail)){
|
|
/* no KVs in store */
|
|
CFSTORE_TP(CFSTORE_TP_FIND, "%s:hkvt is not valid\n", __func__);
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
} else {
|
|
/* CFSTORE_TP(CFSTORE_TP_FIND, "%s:getting hkvt from prev\n", __func__);*/
|
|
ret = cfstore_get_next_hkvt(prev, next);
|
|
if(ret < ARM_DRIVER_OK){
|
|
/* no more matching entries or error.
|
|
* either way, return*/
|
|
return ret;
|
|
}
|
|
}
|
|
if(next->head == NULL){
|
|
/* no entry*/
|
|
CFSTORE_TP(CFSTORE_TP_FIND, "%s:No more entries found\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND;
|
|
}
|
|
/* CFSTORE_TP(CFSTORE_TP_FIND, "%s:cfstore_ctx_g.area_0_head=%p, cfstore_ctx_g.area_0_tail=%p\n", __func__, cfstore_ctx_g.area_0_head, cfstore_ctx_g.area_0_tail);*/
|
|
cfstore_hkvt_dump(next, __func__);
|
|
while(cfstore_hkvt_is_valid(next, ctx->area_0_tail))
|
|
{
|
|
/* CFSTORE_TP(CFSTORE_TP_FIND, "%s:next->head=%p, next->key=%p, next->value=%p, next->tail=%p, \n", __func__, next->head, next->key, next->value, next->tail); */
|
|
cfstore_hkvt_dump(next, __func__);
|
|
|
|
/* if this KV is deleting then proceed to the next item */
|
|
// Note: It is probably better not to enforce policy in this function
|
|
// but in the client
|
|
if(cfstore_hkvt_get_flags_delete(next)){
|
|
ret = cfstore_get_next_hkvt(next, next);
|
|
if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND) {
|
|
CFSTORE_TP(CFSTORE_TP_FIND, "%s:No more KVs found\n", __func__);
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
/* if this KV is not readable by the client then proceed to the next item */
|
|
// Note: It is probably better not to enforce policy in this function
|
|
// but in the client
|
|
if(!cfstore_is_kv_client_readable(next)){
|
|
ret = cfstore_get_next_hkvt(next, next);
|
|
if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND) {
|
|
CFSTORE_TP(CFSTORE_TP_FIND, "%s:No more KVs found\n", __func__);
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
/* check if this key_name matches the query */
|
|
next_key_len = cfstore_hkvt_get_key_len(next);
|
|
next_key_len++;
|
|
cfstore_get_key_name_ex(next, key_name, &next_key_len);
|
|
ret = fnmatch(key_name_query, key_name, 0);
|
|
if(ret == 0){
|
|
/* found the entry in the store. return handle */
|
|
CFSTORE_TP(CFSTORE_TP_FIND, "%s:Found matching key (key_name_query = \"%s\", next->key = \"%s\"),next_key_len=%d\n", __func__, key_name_query, key_name, (int) next_key_len);
|
|
cfstore_hkvt_dump(next, __func__);
|
|
return ARM_DRIVER_OK;
|
|
} else if(ret != CFSTORE_FNM_NOMATCH){
|
|
CFSTORE_ERRLOG("%s:Error: fnmatch() error (ret=%" PRId32 ").\n", __func__, ret);
|
|
return ARM_DRIVER_ERROR;
|
|
}
|
|
/* CFSTORE_FNM_NOMATCH => get the next hkvt if any */
|
|
ret = cfstore_get_next_hkvt(next, next);
|
|
if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND) {
|
|
CFSTORE_TP(CFSTORE_TP_FIND, "%s:No more KVs found\n", __func__);
|
|
break;
|
|
}
|
|
}
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
|
|
/* @brief See definition in configuration_store.h for description. */
|
|
static int32_t cfstore_find(const char* key_name_query, const ARM_CFSTORE_HANDLE previous, ARM_CFSTORE_HANDLE next)
|
|
{
|
|
char key_name[CFSTORE_KEY_NAME_MAX_LENGTH+1];
|
|
uint8_t key_len = 0;
|
|
cfstore_area_hkvt_t hkvt_next;
|
|
cfstore_area_hkvt_t hkvt_previous;
|
|
cfstore_area_hkvt_t *phkvt_previous = NULL;
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
ARM_CFSTORE_FMODE fmode;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
cfstore_client_notify_data_t notify_data;
|
|
|
|
CFSTORE_ASSERT(next != NULL);
|
|
CFSTORE_FENTRYLOG("%s:entered: key_name_query=\"%s\", previous=%p, next=%p\n", __func__, key_name_query, previous, next);
|
|
if(!cfstore_ctx_is_initialised(ctx)) {
|
|
CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
|
|
goto out1;
|
|
}
|
|
/* finding a key doesnt change the sram area so this can happen independently of
|
|
* an oustanding async operation. its unnecessary to check the fsm state */
|
|
ret = cfstore_validate_key_name_query(key_name_query);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: invalid key_name.\n", __func__);
|
|
goto out1;
|
|
}
|
|
ret = cfstore_validate_handle(next);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: invalid next argument.\n", __func__);
|
|
goto out1;
|
|
}
|
|
/* note previous can be NULL if this is the first call the find */
|
|
memset(&hkvt_next, 0, sizeof(hkvt_next));
|
|
memset(&fmode, 0, sizeof(fmode));
|
|
if(previous != NULL && cfstore_file_is_valid(previous, ctx)){
|
|
ret = cfstore_validate_handle(previous);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__);
|
|
goto out1;
|
|
}
|
|
phkvt_previous = &hkvt_previous;
|
|
memset(phkvt_previous, 0, sizeof(hkvt_previous));
|
|
hkvt_previous = cfstore_get_hkvt(previous);
|
|
cfstore_hkvt_dump(&hkvt_previous, __func__);
|
|
if(!cfstore_hkvt_is_valid(phkvt_previous, ctx->area_0_tail)){
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE;
|
|
goto out1;
|
|
}
|
|
} else if(!cfstore_file_is_empty(previous)){
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE_BUF;
|
|
goto out1;
|
|
}
|
|
ret = cfstore_find_ex(key_name_query, phkvt_previous, &hkvt_next);
|
|
if(ret < ARM_DRIVER_OK){
|
|
/* either no more entries or error but either way, return */
|
|
CFSTORE_TP(CFSTORE_TP_FIND, "%s:No more KVs found.\n", __func__);
|
|
goto out2;
|
|
}
|
|
|
|
if(!cfstore_hkvt_is_valid(&hkvt_next, ctx->area_0_tail)){
|
|
CFSTORE_TP(CFSTORE_TP_FIND, "%s:Did not find any matching KVs.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND;
|
|
goto out2;
|
|
}
|
|
|
|
/* Have a valid kv. cfstore_find_ex() checked the client has
|
|
* permission to read the KV, so dont have to perform this check again here. */
|
|
|
|
/* return handle to client */
|
|
cfstore_file_create(&hkvt_next, fmode, next, &ctx->file_list);
|
|
ret = ARM_DRIVER_OK;
|
|
out2:
|
|
/* previous handle is being returned to CFSTORE with this call so destroy file struct */
|
|
if(previous != NULL && cfstore_file_is_valid(previous, ctx))
|
|
{
|
|
/* do not use ret in this stanza as will loose return state from above */
|
|
/* CFSTORE_TP(CFSTORE_TP_FIND, "%s:about to destroy KV, previous=%p.\n", __func__, previous); */
|
|
cfstore_file_dump((cfstore_file_t*) previous, __func__);
|
|
|
|
key_len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
|
|
memset(key_name, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1);
|
|
if(cfstore_get_key_name_ex(&hkvt_next, key_name, &key_len) < ARM_DRIVER_OK){
|
|
/* either no more entries or error but either way, return */
|
|
CFSTORE_TP(CFSTORE_TP_FIND, "%s:debug: cfstore_get_key_name_ex failed or no more kvs.\n", __func__);
|
|
goto out1;
|
|
}
|
|
cfstore_file_destroy(cfstore_file_get(previous));
|
|
/* now get hkvt_next again based on the name to overcome the fact that the hkvt
|
|
* may be invalid due to the possible deletion of the previous KV.x */
|
|
if(cfstore_find_ex(key_name, NULL, &hkvt_next) < ARM_DRIVER_OK){
|
|
/* either no more entries or error but either way, return */
|
|
CFSTORE_TP(CFSTORE_TP_FIND, "%s:find failed key_name=%s ret=%" PRId32 ".\n", __func__, key_name, ret);
|
|
goto out1;
|
|
}
|
|
cfstore_hkvt_dump(&hkvt_next, __func__);
|
|
}
|
|
out1:
|
|
/* Find() always completes synchronously irrespective of flash mode, so indicate to caller */
|
|
cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_FIND, ret, next);
|
|
cfstore_ctx_client_notify(ctx, ¬ify_data);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* @brief grow/shrink pre-existing KV.
|
|
*
|
|
* @note rw_lock must be held by the caller of this function rw_area0_lock */
|
|
static int32_t cfstore_recreate(const char* key_name, ARM_CFSTORE_SIZE value_len, ARM_CFSTORE_HANDLE hkey, cfstore_area_hkvt_t* hkvt)
|
|
{
|
|
uint8_t* ptr = NULL;
|
|
int32_t kv_size_diff = 0;
|
|
ARM_CFSTORE_SIZE area_size = 0;
|
|
ARM_CFSTORE_FMODE flags;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered: key_name=\"%s\", value_len=%d\n", __func__, key_name, (int) value_len);
|
|
cfstore_dump_contents(__func__);
|
|
memset(&flags, 0, sizeof(flags));
|
|
flags.read = true;
|
|
flags.write = true;
|
|
kv_size_diff = value_len - cfstore_hkvt_get_value_len(hkvt);
|
|
if(kv_size_diff == 0){
|
|
/* nothing more to do*/
|
|
CFSTORE_TP(CFSTORE_TP_CREATE, "%s:new value length the same as the old\n", __func__);
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
CFSTORE_TP(CFSTORE_TP_CREATE, "%s:cfstore_ctx_g.area_0_head=%p, cfstore_ctx_g.area_0_tail=%p\n", __func__, ctx->area_0_head, ctx->area_0_tail);
|
|
CFSTORE_TP(CFSTORE_TP_CREATE, "%s:sizeof(header)=%d, sizeof(key)=%d, sizeof(value)=%d, kv_size_diff=%d, area_size=%d\n", __func__, (int) sizeof(cfstore_area_header_t), (int)(strlen(key_name)), (int)value_len, (int) kv_size_diff, (int) area_size);
|
|
|
|
/* grow the area by the size of the new KV */
|
|
area_size = cfstore_ctx_get_area_len();
|
|
if (kv_size_diff < 0){
|
|
/* value blob size shrinking => do memmove() before realloc() which will free memory */
|
|
memmove(hkvt->tail + kv_size_diff, hkvt->tail, ctx->area_0_tail - hkvt->tail);
|
|
//todo: wip: do we have to update file pointers for KVs after the one thats changed size?
|
|
}
|
|
ptr = (uint8_t*) CFSTORE_REALLOC((void*) ctx->area_0_head, area_size + kv_size_diff);
|
|
if(ptr == NULL){
|
|
CFSTORE_ERRLOG("%s:realloc failed for key_name=%s\n", __func__, key_name);
|
|
cfstore_ctx_reset(ctx);
|
|
return ARM_CFSTORE_DRIVER_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
if(ptr != ctx->area_0_head){
|
|
CFSTORE_TP(CFSTORE_TP_CREATE, "%s:cfstore_ctx_g.area_0_head pointer changed (cfstore_ctx_g.area_0_head=%p, cfstore_ctx_g.area_0_tail=%p)\n", __func__, ctx->area_0_head, ptr);
|
|
/* This covers the cases where CFSTORE_REALLOC() has moved the area in memory
|
|
* As realloc() has caused the memory to move, hkvt needs re-initialising */
|
|
hkvt->head += ptr - ctx->area_0_head;
|
|
hkvt->key += ptr - ctx->area_0_head;
|
|
hkvt->value += ptr - ctx->area_0_head;
|
|
hkvt->tail += ptr - ctx->area_0_head;
|
|
/* Set head and tail to old relative position in new area */
|
|
ctx->area_0_head = ptr;
|
|
ctx->area_0_tail = ctx->area_0_head + area_size;
|
|
//todo: wip: do we have to update file pointers for KVs after the memory has moved?
|
|
}
|
|
|
|
if(kv_size_diff > 0) {
|
|
/* value blob size growing requires memmove() after realloc() */
|
|
memset(ctx->area_0_tail, 0, kv_size_diff);
|
|
memmove(hkvt->tail+kv_size_diff, hkvt->tail, ctx->area_0_tail - hkvt->tail);
|
|
//todo: wip: do we have to update file pointers for KVs after the one thats changed size?
|
|
}
|
|
/* hkvt->head, hkvt->key and hkvt->value remain unchanged but hkvt->tail has moved. Update it.*/
|
|
hkvt->tail = hkvt->tail + kv_size_diff;
|
|
|
|
/* set the new value length in the header */
|
|
cfstore_hkvt_set_value_len(hkvt, value_len);
|
|
ctx->area_0_tail = ctx->area_0_head + area_size + kv_size_diff;
|
|
cfstore_file_create(hkvt, flags, hkey, &ctx->file_list);
|
|
ctx->area_dirty_flag = true;
|
|
|
|
#ifdef CFSTORE_DEBUG
|
|
cfstore_hkvt_dump(hkvt, __func__);
|
|
cfstore_dump_contents(__func__);
|
|
#endif
|
|
return ARM_DRIVER_OK;
|
|
}
|
|
|
|
|
|
/* @brief See definition in configuration_store.h for description. */
|
|
static int32_t cfstore_create(const char* key_name, ARM_CFSTORE_SIZE value_len, const ARM_CFSTORE_KEYDESC* kdesc, ARM_CFSTORE_HANDLE hkey)
|
|
{
|
|
bool b_acl_default = false;
|
|
uint8_t* ptr = NULL;
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
int32_t cfstore_uvisor_box_id = 0;
|
|
ARM_CFSTORE_SIZE area_size = 0;
|
|
ARM_CFSTORE_SIZE kv_size = 0;
|
|
ARM_CFSTORE_SIZE realloc_size = 0;
|
|
cfstore_area_header_t* hdr;
|
|
cfstore_area_hkvt_t hkvt;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
ARM_CFSTORE_FMODE flags;
|
|
cfstore_client_notify_data_t notify_data;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered: key_name=\"%s\", value_len=%d, kdesc=%p\n", __func__, key_name, (int)value_len, kdesc);
|
|
CFSTORE_ASSERT(kdesc != NULL);
|
|
CFSTORE_ASSERT(hkey != NULL);
|
|
|
|
memset(&flags, 0, sizeof(flags));
|
|
if(!cfstore_ctx_is_initialised(ctx)) {
|
|
CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
|
|
}
|
|
/* creating a key cannot happen while a flashJournal_log() is pending as it would change the sram area being logged*/
|
|
if(cfstore_flash_journal_is_async_op_pending(ctx)) {
|
|
CFSTORE_TP(CFSTORE_TP_CREATE, "%s:Debug: flash journal operation pending (awaiting asynchronous notification).\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING;
|
|
}
|
|
ret = cfstore_validate_key_name(key_name);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: invalid key_name (%s).\n", __func__, key_name);
|
|
goto out0;
|
|
}
|
|
ret = cfstore_validate_handle(hkey);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__);
|
|
goto out0;
|
|
}
|
|
ret = cfstore_validate_value_len(value_len);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: invalid key_name.\n", __func__);
|
|
goto out0;
|
|
}
|
|
/* check uvisor security */
|
|
if(cfstore_is_client_kv_owner(key_name, &cfstore_uvisor_box_id) != ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: Client has insufficient permissions to create KV.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_NO_PERMISSIONS;
|
|
goto out0;
|
|
}
|
|
/* the cfstore (uvisor) client is the owner of the KV and therefore is permitted to created it */
|
|
/* A null kdesc is permitted if client is growing/shrinking pre-existing key.
|
|
* Hence, find if key_name pre-exists before validating kdesc */
|
|
ret = cfstore_find_ex(key_name, NULL, &hkvt);
|
|
if(ret < ARM_DRIVER_OK && ret != ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND){
|
|
CFSTORE_ERRLOG("%s:CFSTORE find() returned error (%" PRId32 ")\n", __func__, ret);
|
|
goto out1;
|
|
}
|
|
|
|
if(ret != ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND && cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){
|
|
/* found pre-existing entry; */
|
|
if(cfstore_hkvt_get_flags_delete(&hkvt)){
|
|
CFSTORE_ERRLOG("%s:CFSTORE pre-existing KV with key_name=\"%s\" deleting\n", __func__, key_name);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_PREEXISTING_KEY_DELETING;
|
|
goto out1;
|
|
}
|
|
if(kdesc != NULL) {
|
|
CFSTORE_ERRLOG("%s:CFSTORE contains pre-existing KV with key_name=\"%s\". Cannot create a new KV with the same name\n", __func__, key_name);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_PREEXISTING_KEY;
|
|
goto out1;
|
|
}
|
|
|
|
/* client is requesting to grow/shrink pre-existing key */
|
|
ret = cfstore_recreate(key_name, value_len, hkey, &hkvt);
|
|
goto out1;
|
|
}
|
|
/* not a valid hkvt implying the key_name wasnt found */
|
|
|
|
/* create new key */
|
|
ret = cfstore_validate_key_desc(kdesc);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: invalid key descriptor.\n", __func__);
|
|
goto out1;
|
|
}
|
|
/* insert the KV into the area */
|
|
kv_size = strlen(key_name);
|
|
kv_size += value_len;
|
|
kv_size += sizeof(cfstore_area_header_t);
|
|
|
|
/* grow the area by the size of the new KV
|
|
* In the general case the new ((area_size + kv_size) % program_unit > 0). The new area_size is
|
|
* aligned to a program_unit boundary to facilitate r/w to flash and so the memory realloc size
|
|
* is calculated to align, as follows */
|
|
area_size = cfstore_ctx_get_area_len();
|
|
// moved to flash_init() and program_unit stored in ctx
|
|
/*
|
|
status = FlashJournal_getInfo(&ctx->jrnl, &info);
|
|
if(status < JOURNAL_STATUS_OK){
|
|
CFSTORE_TP(CFSTORE_TP_CREATE, "%s:Error: failed get journal info (status=%d)\n", __func__, (int) status);
|
|
ret = cfstore_flash_map_error(status);
|
|
goto out1;
|
|
}
|
|
*/
|
|
/* setup the reallocation memory size. */
|
|
realloc_size = area_size + kv_size;
|
|
if(realloc_size % cfstore_ctx_get_program_unit(ctx) > 0){
|
|
realloc_size += (cfstore_ctx_get_program_unit(ctx) - (realloc_size % cfstore_ctx_get_program_unit(ctx)));
|
|
}
|
|
ptr = (uint8_t*) CFSTORE_REALLOC((void*) ctx->area_0_head, realloc_size);
|
|
if(ptr == NULL){
|
|
CFSTORE_ERRLOG("%s:realloc failed for key_name=%s\n", __func__, key_name);
|
|
cfstore_ctx_reset(ctx);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_OUT_OF_MEMORY;
|
|
goto out1;
|
|
}
|
|
if(ptr != ctx->area_0_head){
|
|
CFSTORE_TP(CFSTORE_TP_CREATE, "%s:cfstore_ctx_g.area_0_head pointer changed (cfstore_ctx_g.area_0_head=%p, cfstore_ctx_g.area_0_tail=%p)\n", __func__, ctx->area_0_head, ptr);
|
|
/* this covers the following cases:
|
|
* - this is the first KV insertion in the area, which is special as both area head/tail pointers need setting.
|
|
* - realloc() has move the area in memory */
|
|
ctx->area_0_head = ptr;
|
|
ctx->area_0_tail = ctx->area_0_head + area_size;
|
|
}
|
|
|
|
/* check realloc() hasnt move area in memory from cfstore_ctx_g.area_0_head*/
|
|
CFSTORE_TP(CFSTORE_TP_CREATE, "%s:cfstore_ctx_g.area_0_head=%p, ptr=%p\n", __func__, ctx->area_0_head, ptr);
|
|
|
|
/* determine if should adopt a default behavior for acl permission setting */
|
|
if(cfstore_acl_is_default(kdesc->acl)){
|
|
/* set as read-write by default default */
|
|
CFSTORE_TP(CFSTORE_TP_CREATE, "%s:Note: No ACL bits set. Adopting default permissions of owner read and write.\n", __func__);
|
|
b_acl_default = true;
|
|
}
|
|
/* set the header up, then copy key_name into header */
|
|
memset(ctx->area_0_tail, 0, kv_size);
|
|
hdr = (cfstore_area_header_t*) ctx->area_0_tail;
|
|
hdr->klength = (uint8_t) strlen(key_name);
|
|
hdr->vlength = value_len;
|
|
hdr->perm_owner_read = b_acl_default ? true : kdesc->acl.perm_owner_read;
|
|
hdr->perm_owner_write = b_acl_default ? true : kdesc->acl.perm_owner_write;
|
|
hdr->perm_owner_execute = kdesc->acl.perm_owner_execute;
|
|
hdr->perm_other_read = kdesc->acl.perm_other_read;
|
|
hdr->perm_other_write = kdesc->acl.perm_other_write;
|
|
hdr->perm_other_execute = kdesc->acl.perm_other_execute;
|
|
strncpy((char*)hdr + sizeof(cfstore_area_header_t), key_name, strlen(key_name));
|
|
/* Updating the area_0_tail pointer reveals the inserted KV to other operations. See [NOTE1] for details.*/
|
|
ctx->area_0_tail = ctx->area_0_head + area_size + kv_size;
|
|
hkvt = cfstore_get_hkvt_from_head_ptr((uint8_t*) hdr);
|
|
if(cfstore_flags_is_default(kdesc->flags)){
|
|
/* set as read-only by default default */
|
|
flags.read = true;
|
|
flags.write = true;
|
|
} else {
|
|
flags.read = kdesc->flags.read;
|
|
flags.write = kdesc->flags.write;
|
|
}
|
|
cfstore_file_create(&hkvt, flags, hkey, &ctx->file_list);
|
|
ctx->area_dirty_flag = true;
|
|
ret = ARM_DRIVER_OK;
|
|
out1:
|
|
cfstore_hkvt_dump(&hkvt, __func__);
|
|
out0:
|
|
cfstore_dump_contents(__func__);
|
|
/* Create() always completes synchronously irrespective of flash mode, so indicate to caller */
|
|
cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_CREATE, ret, hkey);
|
|
cfstore_ctx_client_notify(ctx, ¬ify_data);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* @brief See definition in configuration_store.h for description. */
|
|
static int32_t cfstore_open(const char* key_name, ARM_CFSTORE_FMODE flags, ARM_CFSTORE_HANDLE hkey)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
cfstore_area_hkvt_t hkvt;
|
|
cfstore_file_t *file = NULL;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
cfstore_client_notify_data_t notify_data;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
cfstore_flags_dump(flags, __func__);
|
|
CFSTORE_ASSERT(key_name != NULL);
|
|
CFSTORE_ASSERT(hkey != NULL);
|
|
if(!cfstore_ctx_is_initialised(ctx)) {
|
|
CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
|
|
goto out1;
|
|
}
|
|
ret = cfstore_validate_key_name(key_name);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: invalid key_name.\n", __func__);
|
|
goto out1;
|
|
}
|
|
ret = cfstore_validate_fmode_flags(flags);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: invalid flags.\n", __func__);
|
|
goto out1;
|
|
}
|
|
if(flags.write){
|
|
/* opening a pre-existing key for writing can result in the sram area being changed, which
|
|
* cannot happen while a flashJournal_xxx() async completion notification is outstanding */
|
|
if(cfstore_flash_journal_is_async_op_pending(ctx)) {
|
|
CFSTORE_TP(CFSTORE_TP_OPEN, "%s:Debug: flash journal operation pending (awaiting asynchronous notification).\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING;
|
|
goto out1;
|
|
}
|
|
}
|
|
ret = cfstore_validate_handle(hkey);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__);
|
|
goto out1;
|
|
}
|
|
/* find the KV and return a handle */
|
|
cfstore_hkvt_init(&hkvt);
|
|
ret = cfstore_find_ex(key_name, NULL, &hkvt);
|
|
if(ret < ARM_DRIVER_OK){
|
|
/* either no more entries or error but either way, return */
|
|
CFSTORE_TP(CFSTORE_TP_OPEN, "%s:debug: find failed or no more kvs.\n", __func__);
|
|
goto out1;
|
|
}
|
|
if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail))
|
|
{
|
|
CFSTORE_ERRLOG("%s:Error: Could not find pre-existing key to open with key_name=(%s).\n", __func__, key_name);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND;
|
|
goto out1;
|
|
}
|
|
/* if this KV is deleting then do not allow item to be opened */
|
|
if(cfstore_hkvt_get_flags_delete(&hkvt)){
|
|
CFSTORE_ERRLOG("%s:Error: Pre-existing key key_name=(%s) is deleting.\n", __func__, key_name);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_PREEXISTING_KEY_DELETING;
|
|
goto out1;
|
|
}
|
|
/* key found, check permissions */
|
|
if(cfstore_flags_is_default(flags)){
|
|
/* set as read-only by default default */
|
|
flags.read = true;
|
|
}
|
|
if(flags.read == true && !cfstore_is_kv_client_readable(&hkvt)){
|
|
CFSTORE_ERRLOG("%s:Error: Client has no read access to KV (key_name=%s).\n", __func__, key_name);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_PERM_NO_READ_ACCESS;
|
|
goto out1;
|
|
}
|
|
if(flags.write == true && !cfstore_is_kv_client_writable(&hkvt)){
|
|
CFSTORE_ERRLOG("%s:Error: Client has no write access to KV (key_name=%s).\n", __func__, key_name);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_PERM_NO_WRITE_ACCESS;
|
|
goto out1;
|
|
}
|
|
if(flags.execute == true && !cfstore_is_kv_client_executable(&hkvt)){
|
|
CFSTORE_ERRLOG("%s:Error: Client has no execute access to KV (key_name=%s).\n", __func__, key_name);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_PERM_NO_EXECUTE_ACCESS;
|
|
goto out1;
|
|
}
|
|
/* return handle to client */
|
|
file = cfstore_file_create(&hkvt, flags, hkey, &ctx->file_list);
|
|
if(file) {
|
|
cfstore_file_dump(file, __func__);
|
|
} else {
|
|
CFSTORE_ERRLOG("%s:Error: failed to create file (key_name=%s).\n", __func__, key_name);
|
|
}
|
|
out1:
|
|
/* Open() always completes synchronously irrespective of flash mode, so indicate to caller */
|
|
cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_OPEN, ret, hkey);
|
|
cfstore_ctx_client_notify(ctx, ¬ify_data);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* @brief See definition in configuration_store.h for description. */
|
|
static int32_t cfstore_close(ARM_CFSTORE_HANDLE hkey)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
cfstore_client_notify_data_t notify_data;
|
|
cfstore_area_hkvt_t hkvt;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
if(!cfstore_ctx_is_initialised(ctx)) {
|
|
CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
|
|
goto out0;
|
|
}
|
|
/* closing a key can lead to its deletion, which cannot happening while there are pending
|
|
* async operations outstanding */
|
|
if(cfstore_flash_journal_is_async_op_pending(ctx)) {
|
|
CFSTORE_TP(CFSTORE_TP_CLOSE, "%s:Debug: flash journal operation pending (awaiting asynchronous notification).\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING;
|
|
goto out0;
|
|
}
|
|
ret = cfstore_validate_handle(hkey);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: invalid hkey argument.\n", __func__);
|
|
goto out0;
|
|
}
|
|
/* check the hkey is valid */
|
|
hkvt = cfstore_get_hkvt(hkey);
|
|
if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){
|
|
CFSTORE_ERRLOG("%s:ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE;
|
|
goto out0;
|
|
}
|
|
if(!cfstore_is_kv_client_closable((cfstore_file_t*) hkey)){
|
|
CFSTORE_ERRLOG("%s:Error: client is not permitted to close KV.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_NO_PERMISSIONS;
|
|
goto out0;
|
|
}
|
|
/* delete the file associated with this open handle */
|
|
CFSTORE_TP(CFSTORE_TP_CLOSE, "%s:about to call cfstore_file_destroy().\n", __func__);
|
|
cfstore_file_dump((cfstore_file_t*) hkey, __func__);
|
|
ret = cfstore_file_destroy(cfstore_file_get(hkey));
|
|
out0:
|
|
/* Close() always completes synchronously irrespective of flash mode, so indicate to caller */
|
|
cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_CLOSE, ret, NULL);
|
|
cfstore_ctx_client_notify(ctx, ¬ify_data);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* @brief See definition in configuration_store.h for description. */
|
|
static int32_t cfstore_read(ARM_CFSTORE_HANDLE hkey, void* data, ARM_CFSTORE_SIZE* len)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
ARM_CFSTORE_SIZE read_len = 0;
|
|
cfstore_area_hkvt_t hkvt;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
cfstore_file_t* file = cfstore_file_get(hkey);
|
|
cfstore_client_notify_data_t notify_data;
|
|
|
|
CFSTORE_ASSERT(data);
|
|
CFSTORE_ASSERT(len);
|
|
CFSTORE_FENTRYLOG("%s:entered, hkey=%p\n", __func__, hkey);
|
|
if(!cfstore_ctx_is_initialised(ctx)) {
|
|
CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
|
|
goto out0;
|
|
}
|
|
/* reading KVs doesnt change the sram area so this can happen independently of
|
|
* an oustanding async operation. its unnecessary to check the fsm state */
|
|
ret = cfstore_validate_handle(hkey);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__);
|
|
goto out0;
|
|
}
|
|
if(data == NULL){
|
|
CFSTORE_ERRLOG("%s:Error: invalid read data buffer.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_READ_BUFFER;
|
|
goto out0;
|
|
}
|
|
ret = cfstore_validate_len_ptr(len);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: invalid len argument.\n", __func__);
|
|
goto out0;
|
|
}
|
|
cfstore_hkvt_init(&hkvt);
|
|
hkvt = cfstore_get_hkvt(hkey);
|
|
/* check the hkey is valid */
|
|
if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){
|
|
CFSTORE_ERRLOG("%s:ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE;
|
|
goto out0;
|
|
}
|
|
|
|
if(!cfstore_is_kv_client_readable(&hkvt)){
|
|
CFSTORE_ERRLOG("%s:Error: client does not have permission to read KV.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_PERM_NO_READ_ACCESS;
|
|
goto out0;
|
|
}
|
|
read_len = *len <= (cfstore_hkvt_get_value_len(&hkvt) - file->rlocation) ? *len : cfstore_hkvt_get_value_len(&hkvt) - file->rlocation;
|
|
memcpy(data, hkvt.value + file->rlocation, read_len);
|
|
file->rlocation += read_len;
|
|
*len = read_len;
|
|
ret = read_len;
|
|
out0:
|
|
/* Read() always completes synchronously irrespective of flash mode, so indicate to caller */
|
|
cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_READ, ret, hkey);
|
|
cfstore_ctx_client_notify(ctx, ¬ify_data);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* @brief See definition in configuration_store.h for description. */
|
|
static int32_t cfstore_write(ARM_CFSTORE_HANDLE hkey, const char* data, ARM_CFSTORE_SIZE* len)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
ARM_CFSTORE_SIZE value_len = 0;
|
|
cfstore_area_hkvt_t hkvt;
|
|
cfstore_file_t* file = cfstore_file_get(hkey);
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
cfstore_client_notify_data_t notify_data;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered, hkey=%p\n", __func__, hkey);
|
|
CFSTORE_ASSERT(hkey != NULL);
|
|
CFSTORE_ASSERT(len != NULL);
|
|
if(!cfstore_ctx_is_initialised(ctx)) {
|
|
CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
|
|
goto out0;
|
|
}
|
|
/* writing a key cannot happen while a flashJournal_xxx() async operation is pending */
|
|
if(cfstore_flash_journal_is_async_op_pending(ctx)) {
|
|
CFSTORE_TP(CFSTORE_TP_WRITE, "%s:Debug: flash journal operation pending (awaiting asynchronous notification).\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING;
|
|
goto out0;
|
|
}
|
|
ret = cfstore_validate_handle(hkey);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__);
|
|
goto out0;
|
|
}
|
|
if(data == NULL){
|
|
CFSTORE_ERRLOG("%s:Error: invalid write data buffer.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_WRITE_BUFFER;
|
|
goto out0;
|
|
}
|
|
ret = cfstore_validate_len_ptr(len);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: invalid len argument.\n", __func__);
|
|
goto out0;
|
|
}
|
|
ret = cfstore_validate_value_len(*len);
|
|
if (ret < ARM_DRIVER_OK) {
|
|
CFSTORE_ERRLOG("%s:Error: invalid key_name.\n", __func__);
|
|
goto out0;
|
|
}
|
|
/*check file has write permission set */
|
|
if(!file->flags.write){
|
|
CFSTORE_ERRLOG("%s:Error: KV is read-only.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_KEY_READ_ONLY;
|
|
goto out0;
|
|
}
|
|
memset(&hkvt, 0, sizeof(hkvt));
|
|
hkvt = cfstore_get_hkvt(hkey);
|
|
if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){
|
|
CFSTORE_ERRLOG("%s:Error: ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE;
|
|
goto out0;
|
|
}
|
|
if(!cfstore_is_kv_client_writable(&hkvt)){
|
|
CFSTORE_ERRLOG("%s:Error: client does not have permission to write KV.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_PERM_NO_WRITE_ACCESS;
|
|
goto out0;
|
|
}
|
|
value_len = (ARM_CFSTORE_SIZE) cfstore_hkvt_get_value_len(&hkvt);
|
|
*len = *len < value_len ? *len: value_len;
|
|
memcpy(hkvt.value + file->wlocation, data, *len);
|
|
file->wlocation += *len;
|
|
cfstore_hkvt_dump(&hkvt, __func__);
|
|
ctx->area_dirty_flag = true;
|
|
ret = *len;
|
|
out0:
|
|
/* Write() always completes synchronously irrespective of flash mode, so indicate to caller */
|
|
cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_WRITE, ret, hkey);
|
|
cfstore_ctx_client_notify(ctx, ¬ify_data);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* @brief See definition in configuration_store.h for description. */
|
|
static int32_t cfstore_rseek(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_OFFSET offset)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
cfstore_area_hkvt_t hkvt;
|
|
cfstore_file_t* file = cfstore_file_get(hkey);
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
cfstore_client_notify_data_t notify_data;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
if(!cfstore_ctx_is_initialised(ctx)) {
|
|
CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
|
|
}
|
|
/* read-seeking KVs doesnt change the sram area so this can happen independently of
|
|
* an oustanding async operation. its unnecessary to check the fsm state */
|
|
ret = cfstore_validate_handle(hkey);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__);
|
|
return ret;
|
|
}
|
|
ret = cfstore_validate_value_len(offset);
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: offset (%u) greater than maximum value blob size (%u).\n", __func__, (unsigned int) offset, CFSTORE_VALUE_SIZE_MAX);
|
|
return ret;
|
|
}
|
|
if(!file->flags.read){
|
|
CFSTORE_ERRLOG("%s:Error: KV is not readable.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_KEY_UNREADABLE;
|
|
goto out0;
|
|
|
|
}
|
|
cfstore_hkvt_init(&hkvt);
|
|
hkvt = cfstore_get_hkvt(hkey);
|
|
if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){
|
|
CFSTORE_ERRLOG("%s:Error: ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE;
|
|
goto out0;
|
|
}
|
|
if(!cfstore_is_kv_client_readable(&hkvt)){
|
|
CFSTORE_ERRLOG("%s:Error: client does not have permission to read KV.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_PERM_NO_READ_ACCESS;
|
|
goto out0;
|
|
}
|
|
/* check offset is in range */
|
|
if(offset > cfstore_hkvt_get_value_len(&hkvt)){
|
|
CFSTORE_ERRLOG("%s:Error: seeking beyond end of value.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_SEEK;
|
|
goto out0;
|
|
|
|
}
|
|
file->rlocation = offset;
|
|
ret = (int32_t) offset;
|
|
out0:
|
|
/* Rseek() always completes synchronously irrespective of flash mode, so indicate to caller */
|
|
cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_RSEEK, ret, hkey);
|
|
cfstore_ctx_client_notify(ctx, ¬ify_data);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* @brief See definition in configuration_store.h for description. */
|
|
static int32_t cfstore_flush(void)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
if(!cfstore_ctx_is_initialised(ctx)) {
|
|
CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
|
|
goto out0;
|
|
}
|
|
/* only 1 flush operation can be outstanding so check whether one is already in progress */
|
|
if(cfstore_flash_journal_is_async_op_pending(ctx)) {
|
|
CFSTORE_TP(CFSTORE_TP_FLUSH, "%s:Debug: flash journal operation pending (awaiting asynchronous notification).\n", __func__);
|
|
return ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING;
|
|
}
|
|
ret = cfstore_flash_flush(ctx);
|
|
if(ret < ARM_DRIVER_OK) {
|
|
CFSTORE_ERRLOG("%s:Error: cfstore_flash_flush() returned error (ret=%" PRId32 ").\n", __func__, ret);
|
|
goto out0;
|
|
}
|
|
out0:
|
|
return ret;
|
|
}
|
|
|
|
/* @brief See definition in configuration_store.h for description. */
|
|
static int32_t cfstore_initialise(ARM_CFSTORE_CALLBACK callback, void* client_context)
|
|
{
|
|
int ret = ARM_DRIVER_ERROR;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
#if defined CFSTORE_CONFIG_BACKEND_FLASH_ENABLED && CFSTORE_CONFIG_BACKEND_FLASH_ENABLED == 1
|
|
ARM_STORAGE_CAPABILITIES storage_caps;
|
|
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered: callback=%p, client_context=%p, ref_count=%d\n", __func__, callback, client_context, (int) ctx->init_ref_count);
|
|
/* init cfstore context the first time this method is called
|
|
* note ctx->rw_area0_lock has already been initialised */
|
|
|
|
/* CS protection required to get into the fsm into the initing state, without another client g*/
|
|
cfstore_critical_section_lock(&ctx->rw_area0_lock, __func__);
|
|
if(ctx->init_ref_count == 0)
|
|
{
|
|
CFSTORE_TP(CFSTORE_TP_INIT, "%s:debug: first time init\n", __func__);
|
|
/* perform first time initialisation */
|
|
ctx->init_ref_count++;
|
|
/* initially there is no memory allocated for the area */
|
|
CFSTORE_INIT_LIST_HEAD(&ctx->file_list);
|
|
cfstore_critical_section_init(&ctx->rw_area0_lock);
|
|
ctx->area_0_head = NULL;
|
|
ctx->area_0_tail = NULL;
|
|
|
|
CFSTORE_ASSERT(sizeof(cfstore_file_t) == CFSTORE_HANDLE_BUFSIZE);
|
|
if(sizeof(cfstore_file_t) != CFSTORE_HANDLE_BUFSIZE){
|
|
CFSTORE_ERRLOG("%s:Error: sizeof(cfstore_file_t)=(%d) != CFSTORE_HANDLE_BUFSIZE (%d)\n", __func__,(int) sizeof(cfstore_file_t), (int) CFSTORE_HANDLE_BUFSIZE);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_INTERNAL;
|
|
goto out0;
|
|
}
|
|
ctx->client_callback = callback;
|
|
ctx->client_context = client_context;
|
|
ctx->area_dirty_flag = false;
|
|
ctx->client_callback_notify_flag = false;
|
|
|
|
cfstore_client_notify_data_init(&ctx->client_notify_data, CFSTORE_OPCODE_MAX, ARM_DRIVER_ERROR, NULL);
|
|
ctx->power_state = ARM_POWER_FULL;
|
|
ctx->status = ARM_DRIVER_OK;
|
|
|
|
#if defined CFSTORE_CONFIG_BACKEND_FLASH_ENABLED && CFSTORE_CONFIG_BACKEND_FLASH_ENABLED == 1
|
|
// todo: put in cfstore_flash_init() ?
|
|
/* set the cfstore async flag according to the storage driver mode */
|
|
storage_caps = cfstore_storage_drv->GetCapabilities();
|
|
cfstore_caps_g.asynchronous_ops = storage_caps.asynchronous_ops;
|
|
#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
|
|
|
|
ret = cfstore_flash_init();
|
|
if(ret < ARM_DRIVER_OK) {
|
|
CFSTORE_ERRLOG("%s:Error: failed to initialise flash layer\n", __func__);
|
|
goto out0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CFSTORE_TP(CFSTORE_TP_INIT, "%s:debug: n-th time init\n", __func__);
|
|
/* initialisation already done so only increment the ref count */
|
|
ctx->init_ref_count++;
|
|
ret = ARM_DRIVER_OK;
|
|
}
|
|
/* if not initialised already, fsm now in the initing state so safe to come out of CS */
|
|
cfstore_critical_section_unlock(&ctx->rw_area0_lock, __func__);
|
|
out0:
|
|
CFSTORE_FENTRYLOG("%s:exiting: callback=%p, client_context=%p, ref_count=%d\n", __func__, callback, client_context, (int) ctx->init_ref_count);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* @brief See prototype definition in configuration_store.h for function description.
|
|
*
|
|
* @note unitialising cfstore results in all entries that have not been flushed being lost
|
|
*/
|
|
static int32_t cfstore_uninitialise(void)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
ARM_STORAGE_CAPABILITIES caps;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
memset(&caps, 0, sizeof(caps));
|
|
|
|
if(!cfstore_ctx_is_initialised(ctx)) {
|
|
CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
|
|
goto out;
|
|
}
|
|
/* only uninitialise when there are no flash journal async operations pending*/
|
|
if(cfstore_flash_journal_is_async_op_pending(ctx)) {
|
|
CFSTORE_TP(CFSTORE_TP_INIT, "%s:Debug: flash journal operation pending (awaiting asynchronous notification).\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING;
|
|
goto out;
|
|
}
|
|
if(ctx->init_ref_count > 0) {
|
|
ctx->init_ref_count--;
|
|
CFSTORE_TP(CFSTORE_TP_INIT, "%s:Debug: decemented init_ref_count (%" PRId32 ").\n", __func__, ctx->init_ref_count);
|
|
}
|
|
if(ctx->init_ref_count == 0)
|
|
{
|
|
CFSTORE_TP(CFSTORE_TP_INIT, "%s:Debug: init_ref_count == 0 (%" PRId32 ") so uninitialising.\n", __func__, ctx->init_ref_count);
|
|
/* check file list is empty and if not, free the items */
|
|
if(ctx->file_list.next != ctx->file_list.prev)
|
|
{
|
|
/* list is not empty. walk the list and free the entries */
|
|
// todo: wip: free items on the file list
|
|
}
|
|
|
|
ret = cfstore_flash_deinit();
|
|
if(ret < ARM_DRIVER_OK){
|
|
CFSTORE_ERRLOG("%s:Error: failed to uninitialise flash journal layer.\n", __func__);
|
|
goto out;
|
|
}
|
|
if(ctx->area_0_head){
|
|
CFSTORE_FREE(ctx->area_0_head);
|
|
ctx->area_0_head = NULL;
|
|
ctx->area_0_tail = NULL;
|
|
}
|
|
}
|
|
out:
|
|
/* notify client */
|
|
cfstore_client_notify_data_init(&ctx->client_notify_data, CFSTORE_OPCODE_UNINITIALIZE, ret, NULL);
|
|
cfstore_ctx_client_notify(ctx, &ctx->client_notify_data);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* @brief See definition in configuration_store.h for description. */
|
|
static int32_t cfstore_power_control(ARM_POWER_STATE state)
|
|
{
|
|
int32_t ret = ARM_DRIVER_ERROR;
|
|
cfstore_ctx_t* ctx = cfstore_ctx_get();
|
|
cfstore_client_notify_data_t notify_data;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
if(!cfstore_ctx_is_initialised(ctx)) {
|
|
CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
|
|
ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
|
|
goto out0;
|
|
}
|
|
/* setting power state doesnt change the sram area so this can happen independently of
|
|
* an oustanding async operation. its unnecessary to check the fsm state */
|
|
if(state <= ARM_POWER_FULL){
|
|
ctx->power_state = state;
|
|
/* set return to a positive value*/
|
|
ret = (int32_t) state;
|
|
}
|
|
out0:
|
|
/* PowerControl() always completes synchronously irrespective of flash mode, so indicate to caller */
|
|
cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_POWER_CONTROL, ret, NULL);
|
|
cfstore_ctx_client_notify(ctx, ¬ify_data);
|
|
return ret;
|
|
}
|
|
|
|
|
|
#ifdef YOTTA_CFG_CFSTORE_UVISOR
|
|
|
|
/*
|
|
* uvisor secure gateways for ARM_CFSTORE_DRIVER access methods.
|
|
*/
|
|
|
|
UVISOR_EXTERN int32_t __cfstore_uvisor_close(ARM_CFSTORE_HANDLE hkey)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return cfstore_close(hkey);
|
|
}
|
|
|
|
static int32_t cfstore_uvisor_close(ARM_CFSTORE_HANDLE hkey)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return secure_gateway(configuration_store, __cfstore_uvisor_close, hkey);
|
|
}
|
|
|
|
UVISOR_EXTERN int32_t __cfstore_uvisor_create(const char* key_name, ARM_CFSTORE_SIZE value_len, const ARM_CFSTORE_KEYDESC* kdesc, ARM_CFSTORE_HANDLE hkey)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return cfstore_create(key_name, value_len, kdesc, hkey);
|
|
}
|
|
|
|
static int32_t cfstore_uvisor_create(const char* key_name, ARM_CFSTORE_SIZE value_len, const ARM_CFSTORE_KEYDESC* kdesc, ARM_CFSTORE_HANDLE hkey)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return secure_gateway(configuration_store, __cfstore_uvisor_create, key_name, value_len, kdesc, hkey);
|
|
}
|
|
|
|
UVISOR_EXTERN int32_t __cfstore_uvisor_delete(ARM_CFSTORE_HANDLE hkey)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return cfstore_delete(hkey);
|
|
}
|
|
|
|
static int32_t cfstore_uvisor_delete(ARM_CFSTORE_HANDLE hkey)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return secure_gateway(configuration_store, __cfstore_uvisor_delete, hkey);
|
|
}
|
|
|
|
UVISOR_EXTERN int32_t __cfstore_uvisor_find(const char* key_name_query, const ARM_CFSTORE_HANDLE previous, ARM_CFSTORE_HANDLE next)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return cfstore_find(key_name_query, previous, next);
|
|
}
|
|
|
|
static int32_t cfstore_uvisor_find(const char* key_name_query, const ARM_CFSTORE_HANDLE previous, ARM_CFSTORE_HANDLE next)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return secure_gateway(configuration_store, __cfstore_uvisor_find, key_name_query, previous, next);
|
|
}
|
|
|
|
UVISOR_EXTERN int32_t __cfstore_uvisor_flush(int dummy)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
(void) dummy;
|
|
return cfstore_flush();
|
|
}
|
|
|
|
static int32_t cfstore_uvisor_flush(void)
|
|
{
|
|
int dummy = 0;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return secure_gateway(configuration_store, __cfstore_uvisor_flush, dummy);
|
|
}
|
|
|
|
UVISOR_EXTERN int32_t __cfstore_uvisor_get_key_name(ARM_CFSTORE_HANDLE hkey, char* key_name, uint8_t *key_name_len)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return cfstore_get_key_name(hkey, key_name, key_name_len);
|
|
}
|
|
|
|
static int32_t cfstore_uvisor_get_key_name(ARM_CFSTORE_HANDLE hkey, char* key_name, uint8_t *key_name_len)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return secure_gateway(configuration_store, __cfstore_uvisor_get_key_name, hkey, key_name, key_name_len);
|
|
}
|
|
|
|
UVISOR_EXTERN int32_t __cfstore_uvisor_get_value_len(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_SIZE *value_len)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return cfstore_get_value_len(hkey, value_len);
|
|
}
|
|
|
|
static int32_t cfstore_uvisor_get_value_len(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_SIZE *value_len)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return secure_gateway(configuration_store, __cfstore_uvisor_get_value_len, hkey, value_len);
|
|
}
|
|
|
|
UVISOR_EXTERN int32_t __cfstore_uvisor_initialize(ARM_CFSTORE_CALLBACK callback, void* client_context)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return cfstore_initialise(callback, client_context);
|
|
}
|
|
|
|
static int32_t cfstore_uvisor_initialise(ARM_CFSTORE_CALLBACK callback, void* client_context)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return secure_gateway(configuration_store, __cfstore_uvisor_initialize, callback, client_context);
|
|
}
|
|
|
|
/* type to convert between ARM_CFSTORE_FMODE and uint32 for passing flags through secure gw */
|
|
typedef union cfstore_fmode_flags_t
|
|
{
|
|
ARM_CFSTORE_FMODE flags;
|
|
uint32_t val;
|
|
} cfstore_fmode_flags_t;
|
|
|
|
UVISOR_EXTERN int32_t __cfstore_uvisor_open(const char* key_name, uint32_t flags, ARM_CFSTORE_HANDLE hkey)
|
|
{
|
|
cfstore_fmode_flags_t uflags;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
uflags.val = flags;
|
|
return cfstore_open(key_name, uflags.flags, hkey);
|
|
}
|
|
|
|
static int32_t cfstore_uvisor_open(const char* key_name, ARM_CFSTORE_FMODE flags, ARM_CFSTORE_HANDLE hkey)
|
|
{
|
|
cfstore_fmode_flags_t uflags;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
uflags.flags = flags;
|
|
return secure_gateway(configuration_store, __cfstore_uvisor_open, key_name, uflags.val, hkey);
|
|
}
|
|
|
|
UVISOR_EXTERN int32_t __cfstore_uvisor_read(ARM_CFSTORE_HANDLE hkey, void* data, ARM_CFSTORE_SIZE* len)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return cfstore_read(hkey, data, len);
|
|
}
|
|
|
|
static int32_t cfstore_uvisor_read(ARM_CFSTORE_HANDLE hkey, void* data, ARM_CFSTORE_SIZE* len)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return secure_gateway(configuration_store, __cfstore_uvisor_read, hkey, data, len);
|
|
}
|
|
|
|
UVISOR_EXTERN int32_t __cfstore_uvisor_rseek(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_OFFSET offset)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return cfstore_rseek(hkey, offset);
|
|
}
|
|
|
|
static int32_t cfstore_uvisor_rseek(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_OFFSET offset)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return secure_gateway(configuration_store, __cfstore_uvisor_rseek, hkey, offset);
|
|
}
|
|
|
|
UVISOR_EXTERN int32_t __cfstore_uvisor_uninitialise(int dummy)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
(void) dummy;
|
|
return cfstore_uninitialise();
|
|
}
|
|
|
|
static int32_t cfstore_uvisor_uninitialize(void)
|
|
{
|
|
int dummy = 0;
|
|
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return secure_gateway(configuration_store, __cfstore_uvisor_uninitialise, dummy);
|
|
}
|
|
|
|
UVISOR_EXTERN int32_t __cfstore_uvisor_write(ARM_CFSTORE_HANDLE hkey, const char* data, ARM_CFSTORE_SIZE* len)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return cfstore_write(hkey, data, len);
|
|
}
|
|
|
|
static int32_t cfstore_uvisor_write(ARM_CFSTORE_HANDLE hkey, const char* data, ARM_CFSTORE_SIZE* len)
|
|
{
|
|
CFSTORE_FENTRYLOG("%s:entered\n", __func__);
|
|
return secure_gateway(configuration_store, __cfstore_uvisor_write, hkey, data, len);
|
|
}
|
|
|
|
|
|
ARM_CFSTORE_DRIVER cfstore_driver =
|
|
{
|
|
.Close = cfstore_uvisor_close,
|
|
.Create = cfstore_uvisor_create,
|
|
.Delete= cfstore_uvisor_delete,
|
|
.Find = cfstore_uvisor_find,
|
|
.Flush = cfstore_uvisor_flush,
|
|
.GetCapabilities = cfstore_get_capabilities,
|
|
.GetKeyName = cfstore_uvisor_get_key_name,
|
|
.GetStatus = cfstore_get_status,
|
|
.GetValueLen = cfstore_uvisor_get_value_len,
|
|
.GetVersion = cfstore_get_version,
|
|
.Initialize = cfstore_uvisor_initialise,
|
|
.Open = cfstore_uvisor_open,
|
|
.PowerControl = cfstore_power_control,
|
|
.Read = cfstore_uvisor_read,
|
|
.Rseek = cfstore_uvisor_rseek,
|
|
.Uninitialize = cfstore_uvisor_uninitialize,
|
|
.Write = cfstore_uvisor_write,
|
|
};
|
|
|
|
#else
|
|
|
|
/* non-uvisor interface */
|
|
ARM_CFSTORE_DRIVER cfstore_driver =
|
|
{
|
|
.Close = cfstore_close,
|
|
.Create = cfstore_create,
|
|
.Delete= cfstore_delete,
|
|
.Find = cfstore_find,
|
|
.Flush = cfstore_flush,
|
|
.GetCapabilities = cfstore_get_capabilities,
|
|
.GetKeyName = cfstore_get_key_name,
|
|
.GetStatus = cfstore_get_status,
|
|
.GetValueLen = cfstore_get_value_len,
|
|
.GetVersion = cfstore_get_version,
|
|
.Initialize = cfstore_initialise,
|
|
.Open = cfstore_open,
|
|
.PowerControl = cfstore_power_control,
|
|
.Read = cfstore_read,
|
|
.Rseek = cfstore_rseek,
|
|
.Uninitialize = cfstore_uninitialise,
|
|
.Write = cfstore_write,
|
|
};
|
|
|
|
#endif /* YOTTA_CFG_CFSTORE_UVISOR */
|