diff options
Diffstat (limited to 'components/service/secure_storage/provider/secure_flash_store')
21 files changed, 3667 insertions, 0 deletions
diff --git a/components/service/secure_storage/provider/secure_flash_store/component.cmake b/components/service/secure_storage/provider/secure_flash_store/component.cmake new file mode 100644 index 000000000..2e31c20f9 --- /dev/null +++ b/components/service/secure_storage/provider/secure_flash_store/component.cmake @@ -0,0 +1,16 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +#------------------------------------------------------------------------------- +if (NOT DEFINED TGT) + message(FATAL_ERROR "mandatory parameter TGT is not defined.") +endif() + +target_sources(${TGT} PRIVATE + "${CMAKE_CURRENT_LIST_DIR}/secure_flash_store.c" + "${CMAKE_CURRENT_LIST_DIR}/sfs_provider.c" + "${CMAKE_CURRENT_LIST_DIR}/sfs_utils.c" + ) + diff --git a/components/service/secure_storage/provider/secure_flash_store/flash/component.cmake b/components/service/secure_storage/provider/secure_flash_store/flash/component.cmake new file mode 100644 index 000000000..a2f34e73c --- /dev/null +++ b/components/service/secure_storage/provider/secure_flash_store/flash/component.cmake @@ -0,0 +1,16 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +#------------------------------------------------------------------------------- +if (NOT DEFINED TGT) + message(FATAL_ERROR "mandatory parameter TGT is not defined.") +endif() + +target_sources(${TGT} PRIVATE + "${CMAKE_CURRENT_LIST_DIR}/sfs_flash_info.c" + "${CMAKE_CURRENT_LIST_DIR}/sfs_flash_ram.c" + "${CMAKE_CURRENT_LIST_DIR}/sfs_flash.c" + ) + diff --git a/components/service/secure_storage/provider/secure_flash_store/flash/sfs_flash.c b/components/service/secure_storage/provider/secure_flash_store/flash/sfs_flash.c new file mode 100644 index 000000000..fce796831 --- /dev/null +++ b/components/service/secure_storage/provider/secure_flash_store/flash/sfs_flash.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018-2020, Arm Limited. All rights reserved. + * Copyright (c) 2020 Cypress Semiconductor Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include "sfs_flash.h" + +#ifndef SFS_MAX_BLOCK_DATA_COPY +#define SFS_MAX_BLOCK_DATA_COPY 256 +#endif + +extern const struct sfs_flash_info_t sfs_flash_info_internal; + +const struct sfs_flash_info_t *sfs_flash_get_info(void) +{ + return &sfs_flash_info_internal; +} + +psa_status_t sfs_flash_block_to_block_move(const struct sfs_flash_info_t *info, + uint32_t dst_block, + size_t dst_offset, + uint32_t src_block, + size_t src_offset, + size_t size) +{ + psa_status_t status; + size_t bytes_to_move; + uint8_t dst_block_data_copy[SFS_MAX_BLOCK_DATA_COPY]; + + while (size > 0) { + /* Calculates the number of bytes to move */ + bytes_to_move = SFS_UTILS_MIN(size, SFS_MAX_BLOCK_DATA_COPY); + + /* Reads data from source block and store it in the in-memory copy of + * destination content. + */ + status = info->read(info, src_block, dst_block_data_copy, src_offset, + bytes_to_move); + if (status != PSA_SUCCESS) { + return status; + } + + /* Writes in flash the in-memory block content after modification */ + status = info->write(info, dst_block, dst_block_data_copy, dst_offset, + bytes_to_move); + if (status != PSA_SUCCESS) { + return status; + } + + /* Updates pointers to the source and destination flash regions */ + dst_offset += bytes_to_move; + src_offset += bytes_to_move; + + /* Decrement remaining size to move */ + size -= bytes_to_move; + } + + return PSA_SUCCESS; +} diff --git a/components/service/secure_storage/provider/secure_flash_store/flash/sfs_flash.h b/components/service/secure_storage/provider/secure_flash_store/flash/sfs_flash.h new file mode 100644 index 000000000..18361f206 --- /dev/null +++ b/components/service/secure_storage/provider/secure_flash_store/flash/sfs_flash.h @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2017-2020, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __SFS_FLASH_H__ +#define __SFS_FLASH_H__ + +#include <stddef.h> +#include <stdint.h> + +#include <protocols/service/psa/packed-c/status.h> +#include "../sfs_utils.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Adjust to match the size of the flash device's physical program unit */ +#define SFS_FLASH_PROGRAM_UNIT (0x1) + +/* Invalid block index */ +#define SFS_BLOCK_INVALID_ID 0xFFFFFFFFU + +/* FIXME: Duplicated from flash info */ +#if (SFS_FLASH_PROGRAM_UNIT <= 16) +#define SFS_FLASH_ALIGNMENT SFS_FLASH_PROGRAM_UNIT +#else +#define SFS_FLASH_ALIGNMENT 1 +#endif + +/** + * \brief Provides a compile-time constant for the maximum program unit required + * by any flash device that can be accessed through this interface. + */ +#define SFS_FLASH_MAX_ALIGNMENT SFS_UTILS_MAX(SFS_FLASH_ALIGNMENT, \ + 1) + +/** + * \struct sfs_flash_info_t + * + * \brief Structure containing the required information about a flash device to + * be used by the SFS Flash FS. + */ +struct sfs_flash_info_t { + /** + * \brief Initialize the Flash Interface. + * + * \param[in] info Flash device information + * + * \return Returns PSA_SUCCESS if the function is executed correctly. + * Otherwise, it returns PSA_ERROR_STORAGE_FAILURE. + */ + psa_status_t (*init)(const struct sfs_flash_info_t *info); + + /** + * \brief Reads block data from the position specified by block ID and + * offset. + * + * \param[in] info Flash device information + * \param[in] block_id Block ID + * \param[out] buff Buffer pointer to store the data read + * \param[in] offset Offset position from the init of the block + * \param[in] size Number of bytes to read + * + * \note This function assumes all input values are valid. That is, the + * address range, based on block_id, offset and size, is a valid range + * in flash. + * + * \return Returns PSA_SUCCESS if the function is executed correctly. + * Otherwise, it returns PSA_ERROR_STORAGE_FAILURE. + */ + psa_status_t (*read)(const struct sfs_flash_info_t *info, uint32_t block_id, + uint8_t *buff, size_t offset, size_t size); + + /** + * \brief Writes block data to the position specified by block ID and + * offset. + * + * \param[in] info Flash device information + * \param[in] block_id Block ID + * \param[in] buff Buffer pointer to the write data + * \param[in] offset Offset position from the init of the block + * \param[in] size Number of bytes to write + * + * \note This function assumes all input values are valid. That is, the + * address range, based on block_id, offset and size, is a valid range + * in flash. + * + * \return Returns PSA_SUCCESS if the function is executed correctly. + * Otherwise, it returns PSA_ERROR_STORAGE_FAILURE. + */ + psa_status_t (*write)(const struct sfs_flash_info_t *info, + uint32_t block_id, const uint8_t *buff, size_t offset, + size_t size); + + /** + * \brief Flushes modifications to a block to flash. Must be called after a + * sequence of calls to write() (including via + * sfs_flash_block_to_block_move()) for one block ID, before any call + * to the same functions for a different block ID. + * + * \param[in] info Flash device information + * + * \note It is permitted for write() to commit block updates immediately, in + * which case this function is a no-op. + * + * \return Returns PSA_SUCCESS if the function is executed correctly. + * Otherwise, it returns PSA_ERROR_STORAGE_FAILURE. + */ + psa_status_t (*flush)(const struct sfs_flash_info_t *info); + + /** + * \brief Erases block ID data. + * + * \param[in] info Flash device information + * \param[in] block_id Block ID + * + * \note This function assumes the input value is valid. + * + * \return Returns PSA_SUCCESS if the function is executed correctly. + * Otherwise, it returns PSA_ERROR_STORAGE_FAILURE. + */ + psa_status_t (*erase)(const struct sfs_flash_info_t *info, + uint32_t block_id); + + void *flash_dev; /**< Pointer to the flash device */ + uint32_t flash_area_addr; /**< Start address of the flash area */ + uint16_t sector_size; /**< Size of the flash device's physical erase + * unit + */ + uint16_t block_size; /**< Size of a logical erase unit presented by the + * flash interface, a multiple of sector_size. + */ + uint16_t num_blocks; /**< Number of logical erase blocks */ + uint16_t program_unit; /**< Minimum size of a program operation */ + uint16_t max_file_size; /**< Maximum file size */ + uint16_t max_num_files; /**< Maximum number of files */ + uint8_t erase_val; /**< Value of a byte after erase (usually 0xFF) */ +}; + +/** + * \brief Gets the flash info structure for the provided flash device. + * + * \return Pointer to the flash info struct. + */ +const struct sfs_flash_info_t *sfs_flash_get_info(void); + +/** + * \brief Moves data from source block ID to destination block ID. + * + * \param[in] info Flash device information + * \param[in] dst_block Destination block ID + * \param[in] dst_offset Destination offset position from the init of the + * destination block + * \param[in] src_block Source block ID + * \param[in] src_offset Source offset position from the init of the source + * block + * \param[in] size Number of bytes to moves + * + * \note This function assumes all input values are valid. That is, the address + * range, based on blockid, offset and size, is a valid range in flash. + * It also assumes that the destination block is already erased and ready + * to be written. + * + * \return Returns PSA_SUCCESS if the function is executed correctly. Otherwise, + * it returns PSA_ERROR_STORAGE_FAILURE. + */ +psa_status_t sfs_flash_block_to_block_move(const struct sfs_flash_info_t *info, + uint32_t dst_block, + size_t dst_offset, + uint32_t src_block, + size_t src_offset, + size_t size); + +#ifdef __cplusplus +} +#endif + +#endif /* __SFS_FLASH_H__ */ diff --git a/components/service/secure_storage/provider/secure_flash_store/flash/sfs_flash_info.c b/components/service/secure_storage/provider/secure_flash_store/flash/sfs_flash_info.c new file mode 100644 index 000000000..7dfe803e5 --- /dev/null +++ b/components/service/secure_storage/provider/secure_flash_store/flash/sfs_flash_info.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "sfs_flash.h" +#include "sfs_flash_ram.h" +#include "../sfs_utils.h" + +#define SFS_FLASH_AREA_ADDR (0x0) + +/* Adjust to a size that will allow all assets to fit */ +#define SFS_FLASH_AREA_SIZE (0x4000) + +/* Adjust to match the size of the flash device's physical erase unit */ +#define SFS_SECTOR_SIZE (0x1000) + +/* Adjust so that the maximum required asset size will fit in one block */ +#define SFS_SECTORS_PER_BLOCK (0x1) + +/* Adjust to match the size of the flash device's physical program unit */ +#define SFS_FLASH_PROGRAM_UNIT (0x1) + +/* The maximum asset size to be stored in the SFS area */ +#define SFS_MAX_ASSET_SIZE (4096) + +/* The maximum number of assets to be stored in the SFS area */ +#define SFS_NUM_ASSETS (10) + +/* Calculate the block layout */ +#define FLASH_INFO_BLOCK_SIZE (SFS_SECTOR_SIZE * SFS_SECTORS_PER_BLOCK) +#define FLASH_INFO_NUM_BLOCKS (SFS_FLASH_AREA_SIZE / FLASH_INFO_BLOCK_SIZE) + +/* Maximum file size */ +#define FLASH_INFO_MAX_FILE_SIZE SFS_UTILS_ALIGN(SFS_MAX_ASSET_SIZE, \ + SFS_FLASH_ALIGNMENT) + +/* Maximum number of files */ +#define FLASH_INFO_MAX_NUM_FILES SFS_NUM_ASSETS + +/* Default value of each byte in the flash when erased */ +#define FLASH_INFO_ERASE_VAL 0xFFU + +/* Allocate a static buffer to emulate storage in RAM */ +static uint8_t sfs_block_data[FLASH_INFO_BLOCK_SIZE * FLASH_INFO_NUM_BLOCKS]; +#define FLASH_INFO_DEV sfs_block_data + +const struct sfs_flash_info_t sfs_flash_info_internal = { + .init = sfs_flash_ram_init, + .read = sfs_flash_ram_read, + .write = sfs_flash_ram_write, + .flush = sfs_flash_ram_flush, + .erase = sfs_flash_ram_erase, + .flash_dev = (void *)FLASH_INFO_DEV, + .flash_area_addr = SFS_FLASH_AREA_ADDR, + .sector_size = SFS_SECTOR_SIZE, + .block_size = FLASH_INFO_BLOCK_SIZE, + .num_blocks = FLASH_INFO_NUM_BLOCKS, + .program_unit = SFS_FLASH_ALIGNMENT, + .max_file_size = FLASH_INFO_MAX_FILE_SIZE, + .max_num_files = FLASH_INFO_MAX_NUM_FILES, + .erase_val = FLASH_INFO_ERASE_VAL, +}; + +/* Checks at compile time that the flash device configuration is valid */ +#include "../flash_fs/sfs_flash_fs_check_info.h" diff --git a/components/service/secure_storage/provider/secure_flash_store/flash/sfs_flash_ram.c b/components/service/secure_storage/provider/secure_flash_store/flash/sfs_flash_ram.c new file mode 100644 index 000000000..e4af6e610 --- /dev/null +++ b/components/service/secure_storage/provider/secure_flash_store/flash/sfs_flash_ram.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2019-2020, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include "sfs_flash_ram.h" +#include <string.h> + +/** + * \brief Gets physical address of the given block ID. + * + * \param[in] info Flash device information + * \param[in] block_id Block ID + * \param[in] offset Offset position from the init of the block + * + * \returns Returns physical address for the given block ID. + */ +static uint32_t get_phys_address(const struct sfs_flash_info_t *info, + uint32_t block_id, size_t offset) +{ + return (block_id * info->block_size) + offset; +} + +psa_status_t sfs_flash_ram_init(const struct sfs_flash_info_t *info) +{ + /* Nothing needs to be done in case of flash emulated in RAM */ + (void)info; + return PSA_SUCCESS; +} + +psa_status_t sfs_flash_ram_read(const struct sfs_flash_info_t *info, + uint32_t block_id, uint8_t *buff, size_t offset, + size_t size) +{ + uint32_t idx = get_phys_address(info, block_id, offset); + + (void)memcpy(buff, (uint8_t *)info->flash_dev + idx, size); + + return PSA_SUCCESS; +} + +psa_status_t sfs_flash_ram_write(const struct sfs_flash_info_t *info, + uint32_t block_id, const uint8_t *buff, + size_t offset, size_t size) +{ + uint32_t idx = get_phys_address(info, block_id, offset); + + (void)memcpy((uint8_t *)info->flash_dev + idx, buff, size); + + return PSA_SUCCESS; +} + +psa_status_t sfs_flash_ram_flush(const struct sfs_flash_info_t *info) +{ + /* Nothing needs to be done for flash emulated in RAM, as writes are + * commited immediately. + */ + (void)info; + return PSA_SUCCESS; +} + +psa_status_t sfs_flash_ram_erase(const struct sfs_flash_info_t *info, + uint32_t block_id) +{ + uint32_t idx = get_phys_address(info, block_id, 0); + + (void)memset((uint8_t *)info->flash_dev + idx, info->erase_val, + info->block_size); + + return PSA_SUCCESS; +} diff --git a/components/service/secure_storage/provider/secure_flash_store/flash/sfs_flash_ram.h b/components/service/secure_storage/provider/secure_flash_store/flash/sfs_flash_ram.h new file mode 100644 index 000000000..eecc5e57e --- /dev/null +++ b/components/service/secure_storage/provider/secure_flash_store/flash/sfs_flash_ram.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019-2020, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +/** + * \file sfs_flash_ram.h + * + * \brief Implementations of the flash interface functions for an emulated flash + * device using RAM. See sfs_flash.h for full documentation of functions. + */ + +#include "sfs_flash.h" + +/** + * \brief Initialize the Flash Interface. + */ +psa_status_t sfs_flash_ram_init(const struct sfs_flash_info_t *info); + +/** + * \brief Reads block data from the position specified by block ID and offset. + */ +psa_status_t sfs_flash_ram_read(const struct sfs_flash_info_t *info, + uint32_t block_id, uint8_t *buff, size_t offset, + size_t size); + +/** + * \brief Writes block data to the position specified by block ID and offset. + */ +psa_status_t sfs_flash_ram_write(const struct sfs_flash_info_t *info, + uint32_t block_id, const uint8_t *buff, + size_t offset, size_t size); + +/** + * \brief Flushes modifications to a block to flash. + */ +psa_status_t sfs_flash_ram_flush(const struct sfs_flash_info_t *info); + +/** + * \brief Erases block ID data. + */ +psa_status_t sfs_flash_ram_erase(const struct sfs_flash_info_t *info, + uint32_t block_id); diff --git a/components/service/secure_storage/provider/secure_flash_store/flash_fs/component.cmake b/components/service/secure_storage/provider/secure_flash_store/flash_fs/component.cmake new file mode 100644 index 000000000..a48270340 --- /dev/null +++ b/components/service/secure_storage/provider/secure_flash_store/flash_fs/component.cmake @@ -0,0 +1,16 @@ +#------------------------------------------------------------------------------- +# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# +#------------------------------------------------------------------------------- +if (NOT DEFINED TGT) + message(FATAL_ERROR "mandatory parameter TGT is not defined.") +endif() + +target_sources(${TGT} PRIVATE + "${CMAKE_CURRENT_LIST_DIR}/sfs_flash_fs_dblock.c" + "${CMAKE_CURRENT_LIST_DIR}/sfs_flash_fs_mblock.c" + "${CMAKE_CURRENT_LIST_DIR}/sfs_flash_fs.c" + ) + diff --git a/components/service/secure_storage/provider/secure_flash_store/flash_fs/sfs_flash_fs.c b/components/service/secure_storage/provider/secure_flash_store/flash_fs/sfs_flash_fs.c new file mode 100644 index 000000000..4747e9914 --- /dev/null +++ b/components/service/secure_storage/provider/secure_flash_store/flash_fs/sfs_flash_fs.c @@ -0,0 +1,468 @@ +/* + * Copyright (c) 2018-2020, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include "sfs_flash_fs.h" + +#include "sfs_flash_fs_dblock.h" +#include "../sfs_utils.h" +#include <string.h> + +#define SFS_FLASH_FS_INIT_FILE 0 + +static psa_status_t sfs_flash_fs_file_write_aligned_data( + struct sfs_flash_fs_ctx_t *fs_ctx, + const struct sfs_block_meta_t *block_meta, + const struct sfs_file_meta_t *file_meta, + size_t offset, + size_t size, + const uint8_t *data) +{ +#if (SFS_FLASH_MAX_ALIGNMENT != 1) + /* Check that the offset is aligned with the flash program unit */ + if (!SFS_UTILS_IS_ALIGNED(offset, fs_ctx->flash_info->program_unit)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + /* Set the size to be aligned with the flash program unit */ + size = SFS_UTILS_ALIGN(size, fs_ctx->flash_info->program_unit); +#endif + + /* It is not permitted to create gaps in the file */ + if (offset > file_meta->cur_size) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + /* Check that the new data is contained within the file's max size */ + if (sfs_utils_check_contained_in(file_meta->max_size, offset, size) + != PSA_SUCCESS) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + return sfs_flash_fs_dblock_write_file(fs_ctx, block_meta, file_meta, offset, + size, data); +} + +psa_status_t sfs_flash_fs_prepare(struct sfs_flash_fs_ctx_t *fs_ctx, + const struct sfs_flash_info_t *flash_info) +{ + /* Associate the flash device info with the context */ + fs_ctx->flash_info = flash_info; + + /* Initialize metadata block with the valid/active metablock */ + return sfs_flash_fs_mblock_init(fs_ctx); +} + +psa_status_t sfs_flash_fs_wipe_all(struct sfs_flash_fs_ctx_t *fs_ctx) +{ + /* Clean and initialize the metadata block */ + return sfs_flash_fs_mblock_reset_metablock(fs_ctx); +} + +psa_status_t sfs_flash_fs_file_exist(struct sfs_flash_fs_ctx_t *fs_ctx, + const uint8_t *fid) +{ + int32_t err; + uint32_t idx; + + err = sfs_flash_fs_mblock_get_file_idx(fs_ctx, fid, &idx); + if (err != PSA_SUCCESS) { + return PSA_ERROR_DOES_NOT_EXIST; + } + + return PSA_SUCCESS; +} + +psa_status_t sfs_flash_fs_file_create(struct sfs_flash_fs_ctx_t *fs_ctx, + const uint8_t *fid, + size_t max_size, + size_t data_size, + uint32_t flags, + const uint8_t *data) +{ + struct sfs_block_meta_t block_meta; + uint32_t cur_phys_block; + int32_t err; + uint32_t idx; + struct sfs_file_meta_t file_meta; + +#if (SFS_FLASH_MAX_ALIGNMENT != 1) + /* Set the max_size to be aligned with the flash program unit */ + max_size = SFS_UTILS_ALIGN(max_size, fs_ctx->flash_info->program_unit); +#endif + + /* Check that the file's maximum size is valid */ + if (max_size > fs_ctx->flash_info->max_file_size) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + /* Check if file already exists */ + err = sfs_flash_fs_mblock_get_file_idx(fs_ctx, fid, &idx); + if (err == PSA_SUCCESS) { + /* If it exists return an error as needs to be removed first */ + return PSA_ERROR_INVALID_ARGUMENT; + } + + /* Try to reserve an file based on the input parameters */ + err = sfs_flash_fs_mblock_reserve_file(fs_ctx, fid, max_size, flags, &idx, + &file_meta, &block_meta); + if (err != PSA_SUCCESS) { + return err; + } + + /* Check if data needs to be stored in the new file */ + if (data_size != 0) { + /* Write the content into scratch data block */ + err = sfs_flash_fs_file_write_aligned_data(fs_ctx, &block_meta, + &file_meta, + SFS_FLASH_FS_INIT_FILE, + data_size, + data); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + + /* Add current size to the file metadata */ + file_meta.cur_size = data_size; + + cur_phys_block = block_meta.phy_id; + + /* Cur scratch block become the active datablock */ + block_meta.phy_id = + sfs_flash_fs_mblock_cur_data_scratch_id(fs_ctx, file_meta.lblock); + + /* Swap the scratch data block */ + sfs_flash_fs_mblock_set_data_scratch(fs_ctx, cur_phys_block, + file_meta.lblock); + } + + /* Update metadata block information */ + err = sfs_flash_fs_mblock_update_scratch_block_meta(fs_ctx, + file_meta.lblock, + &block_meta); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + + /* Add file metadata in the metadata block */ + err = sfs_flash_fs_mblock_update_scratch_file_meta(fs_ctx, idx, &file_meta); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + + /* Copy rest of the file metadata entries */ + err = sfs_flash_fs_mblock_cp_remaining_file_meta(fs_ctx, idx); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + + /* The file data in the logical block 0 is stored in same physical block + * where the metadata is stored. A change in the metadata requires a + * swap of physical blocks. So, the file data stored in the current + * metadata block needs to be copied in the scratch block, if the data + * of the file processed is not located in the logical block 0. When an + * file data is located in the logical block 0, that copy has been done + * while processing the file data. + */ + if ((file_meta.lblock != SFS_LOGICAL_DBLOCK0) || (data_size == 0)) { + err = sfs_flash_fs_mblock_migrate_lb0_data_to_scratch(fs_ctx); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + } + + /* Write metadata header, swap metadata blocks and erase scratch blocks */ + return sfs_flash_fs_mblock_meta_update_finalize(fs_ctx); +} + +psa_status_t sfs_flash_fs_file_get_info(struct sfs_flash_fs_ctx_t *fs_ctx, + const uint8_t *fid, + struct sfs_file_info_t *info) +{ + int32_t err; + uint32_t idx; + struct sfs_file_meta_t tmp_metadata; + + /* Get the meta data index */ + err = sfs_flash_fs_mblock_get_file_idx(fs_ctx, fid, &idx); + if (err != PSA_SUCCESS) { + return PSA_ERROR_DOES_NOT_EXIST; + } + + /* Read file metadata */ + err = sfs_flash_fs_mblock_read_file_meta(fs_ctx, idx, &tmp_metadata); + if (err != PSA_SUCCESS) { + return err; + } + + /* Check if index is still referring to same file */ + if (memcmp(fid, tmp_metadata.id, SFS_FILE_ID_SIZE)) { + return PSA_ERROR_DOES_NOT_EXIST; + } + + info->size_max = tmp_metadata.max_size; + info->size_current = tmp_metadata.cur_size; + info->flags = tmp_metadata.flags; + + return PSA_SUCCESS; +} + +psa_status_t sfs_flash_fs_file_write(struct sfs_flash_fs_ctx_t *fs_ctx, + const uint8_t *fid, + size_t size, + size_t offset, + const uint8_t *data) +{ + struct sfs_block_meta_t block_meta; + uint32_t cur_phys_block; + int32_t err; + uint32_t idx; + struct sfs_file_meta_t file_meta; + + /* Get the file index */ + err = sfs_flash_fs_mblock_get_file_idx(fs_ctx, fid, &idx); + if (err != PSA_SUCCESS) { + return PSA_ERROR_DOES_NOT_EXIST; + } + + /* Read file metadata */ + err = sfs_flash_fs_mblock_read_file_meta(fs_ctx, idx, &file_meta); + if (err != PSA_SUCCESS) { + return PSA_ERROR_DOES_NOT_EXIST; + } + + /* Read block metadata */ + err = sfs_flash_fs_mblock_read_block_metadata(fs_ctx, file_meta.lblock, + &block_meta); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + + /* Write the content into scratch data block */ + err = sfs_flash_fs_file_write_aligned_data(fs_ctx, &block_meta, &file_meta, + offset, size, data); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + + /* Update the file's current size if required */ + if (offset + size > file_meta.cur_size) { + /* Update the file metadata */ + file_meta.cur_size = offset + size; + } + + cur_phys_block = block_meta.phy_id; + + /* Cur scratch block become the active datablock */ + block_meta.phy_id = + sfs_flash_fs_mblock_cur_data_scratch_id(fs_ctx, file_meta.lblock); + + /* Swap the scratch data block */ + sfs_flash_fs_mblock_set_data_scratch(fs_ctx, cur_phys_block, + file_meta.lblock); + + /* Update block metadata in scratch metadata block */ + err = sfs_flash_fs_mblock_update_scratch_block_meta(fs_ctx, + file_meta.lblock, + &block_meta); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + + /* Update file metadata to reflect new attributes */ + err = sfs_flash_fs_mblock_update_scratch_file_meta(fs_ctx, idx, &file_meta); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + + /* Copy rest of the file metadata entries */ + err = sfs_flash_fs_mblock_cp_remaining_file_meta(fs_ctx, idx); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + + /* The file data in the logical block 0 is stored in same physical block + * where the metadata is stored. A change in the metadata requires a + * swap of physical blocks. So, the file data stored in the current + * metadata block needs to be copied in the scratch block, if the data + * of the file processed is not located in the logical block 0. When an + * file data is located in the logical block 0, that copy has been done + * while processing the file data. + */ + if (file_meta.lblock != SFS_LOGICAL_DBLOCK0) { + err = sfs_flash_fs_mblock_migrate_lb0_data_to_scratch(fs_ctx); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + } + + /* Update the metablock header, swap scratch and active blocks, + * erase scratch blocks. + */ + return sfs_flash_fs_mblock_meta_update_finalize(fs_ctx); +} + +psa_status_t sfs_flash_fs_file_delete(struct sfs_flash_fs_ctx_t *fs_ctx, + const uint8_t *fid) +{ + size_t del_file_data_idx; + uint32_t del_file_lblock; + uint32_t del_file_idx; + size_t del_file_max_size; + psa_status_t err; + size_t src_offset = fs_ctx->flash_info->block_size; + size_t nbr_bytes_to_move = 0; + uint32_t idx; + struct sfs_file_meta_t file_meta; + + /* Get the file index */ + err = sfs_flash_fs_mblock_get_file_idx(fs_ctx, fid, &del_file_idx); + if (err != PSA_SUCCESS) { + return PSA_ERROR_DOES_NOT_EXIST; + } + + err = sfs_flash_fs_mblock_read_file_meta(fs_ctx, del_file_idx, &file_meta); + if (err != PSA_SUCCESS) { + return err; + } + + if (sfs_utils_validate_fid(file_meta.id) != PSA_SUCCESS) { + return PSA_ERROR_DOES_NOT_EXIST; + } + + /* Save logical block, data_index and max_size to be used later on */ + del_file_lblock = file_meta.lblock; + del_file_data_idx = file_meta.data_idx; + del_file_max_size = file_meta.max_size; + + /* Remove file metadata */ + file_meta = (struct sfs_file_meta_t){0}; + + /* Update file metadata in to the scratch block */ + err = sfs_flash_fs_mblock_update_scratch_file_meta(fs_ctx, del_file_idx, + &file_meta); + if (err != PSA_SUCCESS) { + return err; + } + + /* Read all file metadata */ + for (idx = 0; idx < fs_ctx->flash_info->max_num_files; idx++) { + if (idx == del_file_idx) { + /* Skip deleted file */ + continue; + } + + /* Read file meta for the given file index */ + err = sfs_flash_fs_mblock_read_file_meta(fs_ctx, idx, &file_meta); + if (err != PSA_SUCCESS) { + return err; + } + + /* Check if the file is located in the same logical block and has a + * valid FID. + */ + if ((file_meta.lblock == del_file_lblock) && + (sfs_utils_validate_fid(file_meta.id) == PSA_SUCCESS)) { + /* If a file is located after the data to delete, this + * needs to be moved. + */ + if (file_meta.data_idx > del_file_data_idx) { + /* Check if this is the position after the deleted + * data. This will be the first file data to move. + */ + if (src_offset > file_meta.data_idx) { + src_offset = file_meta.data_idx; + } + + /* Set the new file data index location in the + * data block. + */ + file_meta.data_idx -= del_file_max_size; + + /* Increase number of bytes to move */ + nbr_bytes_to_move += file_meta.max_size; + } + } + /* Update file metadata in to the scratch block */ + err = sfs_flash_fs_mblock_update_scratch_file_meta(fs_ctx, idx, + &file_meta); + if (err != PSA_SUCCESS) { + return err; + } + } + + /* Compact data block */ + err = sfs_flash_fs_dblock_compact_block(fs_ctx, del_file_lblock, + del_file_max_size, + src_offset, del_file_data_idx, + nbr_bytes_to_move); + if (err != PSA_SUCCESS) { + return err; + } + + /* The file data in the logical block 0 is stored in same physical block + * where the metadata is stored. A change in the metadata requires a + * swap of physical blocks. So, the file data stored in the current + * metadata block needs to be copied in the scratch block, if the data + * of the file processed is not located in the logical block 0. When an + * file data is located in the logical block 0, that copy has been done + * while processing the file data. + */ + if (del_file_lblock != SFS_LOGICAL_DBLOCK0) { + err = sfs_flash_fs_mblock_migrate_lb0_data_to_scratch(fs_ctx); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + } + + /* Update the metablock header, swap scratch and active blocks, + * erase scratch blocks. + */ + return sfs_flash_fs_mblock_meta_update_finalize(fs_ctx); +} + +psa_status_t sfs_flash_fs_file_read(struct sfs_flash_fs_ctx_t *fs_ctx, + const uint8_t *fid, + size_t size, + size_t offset, + uint8_t *data) +{ + psa_status_t err; + uint32_t idx; + struct sfs_file_meta_t tmp_metadata; + + /* Get the file index */ + err = sfs_flash_fs_mblock_get_file_idx(fs_ctx, fid, &idx); + if (err != PSA_SUCCESS) { + return PSA_ERROR_DOES_NOT_EXIST; + } + + /* Read file metadata */ + err = sfs_flash_fs_mblock_read_file_meta(fs_ctx, idx, &tmp_metadata); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + + /* Check if index is still referring to same file */ + if (memcmp(fid, tmp_metadata.id, SFS_FILE_ID_SIZE)) { + return PSA_ERROR_DOES_NOT_EXIST; + } + + /* Boundary check the incoming request */ + err = sfs_utils_check_contained_in(tmp_metadata.cur_size, offset, size); + if (err != PSA_SUCCESS) { + return err; + } + + /* Read the file from flash */ + err = sfs_flash_fs_dblock_read_file(fs_ctx, &tmp_metadata, offset, size, + data); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + + return PSA_SUCCESS; +} diff --git a/components/service/secure_storage/provider/secure_flash_store/flash_fs/sfs_flash_fs.h b/components/service/secure_storage/provider/secure_flash_store/flash_fs/sfs_flash_fs.h new file mode 100644 index 000000000..704c79350 --- /dev/null +++ b/components/service/secure_storage/provider/secure_flash_store/flash_fs/sfs_flash_fs.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2018-2020, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +/** + * \file sfs_flash_fs.h + * + * \brief The purpose of this abstraction is to have the ability to plug-in + * other filesystems or filesystem proxies (supplicant). + */ + +#ifndef __SFS_FLASH_FS_H__ +#define __SFS_FLASH_FS_H__ + +#include <stddef.h> +#include <stdint.h> + +#include "sfs_flash_fs_mblock.h" +#include <protocols/service/psa/packed-c/status.h> +#include "../flash/sfs_flash.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SFS flash filesytem context type, used to maintain state across FS + * operations. + * + * \details The user should allocate a variable of this type, initialised to + * zero, before calling sfs_flash_fs_prepare, and then pass it to each + * subsequent FS operation. The contents are internal to the filesytem. + */ +typedef struct sfs_flash_fs_ctx_t sfs_flash_fs_ctx_t; + +/*! + * \struct sfs_file_info_t + * + * \brief Structure to store the file information. + */ +struct sfs_file_info_t { + size_t size_current; /*!< The current size of the flash file data */ + size_t size_max; /*!< The maximum size of the flash file data in + * bytes. + */ + uint32_t flags; /*!< Flags set when the file was created */ +}; + +/** + * \brief Prepares the filesystem to accept operations on the files. + * + * \param[in,out] fs_ctx Filesystem context to prepare. Must have been + * initialised by the caller. + * \param[in] flash_info Struct containing information about the flash + * device to associate with the context. + * + * \return Returns error code as specified in \ref psa_status_t + */ +psa_status_t sfs_flash_fs_prepare(sfs_flash_fs_ctx_t *fs_ctx, + const struct sfs_flash_info_t *flash_info); + +/** + * \brief Wipes all files from the filesystem. + * + * \param[in,out] fs_ctx Filesystem context to wipe. Must be prepared again + * before further use. + * + * \return Returns error code as specified in \ref psa_status_t + */ +psa_status_t sfs_flash_fs_wipe_all(sfs_flash_fs_ctx_t *fs_ctx); + +/** + * \brief Checks if a file exists in the filesystem. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] fid File ID + * + * \return Returns PSA_SUCCESS if the file exists. If file does not exist, it + * returns PSA_ERROR_DOES_NOT_EXIST. Otherwise, it returns error code as + * specified in \ref psa_status_t. + */ +psa_status_t sfs_flash_fs_file_exist(sfs_flash_fs_ctx_t *fs_ctx, + const uint8_t *fid); + +/** + * \brief Creates a file in the filesystem. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] fid File ID + * \param[in] max_size Size of the file to be created + * \param[in] data_size Size of the incoming buffer. This parameter is set + * to 0 when the file is empty after the creation. + * \param[in] flags Flags of the file + * \param[in] data Pointer to buffer containing the initial data. + * This parameter is set to NULL when the file is + * empty after the creation. + * + * \return Returns PSA_SUCCESS if the file has been created correctly. If the + * fid is in use, it returns PSA_ERROR_INVALID_ARGUMENT. Otherwise, it + * returns error code as specified in \ref psa_status_t. + */ +psa_status_t sfs_flash_fs_file_create(sfs_flash_fs_ctx_t *fs_ctx, + const uint8_t *fid, + size_t max_size, + size_t data_size, + uint32_t flags, + const uint8_t *data); + +/** + * \brief Gets the file information referenced by the file ID. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] fid File ID + * \param[out] info Pointer to the information structure to store the + * file information values \ref sfs_file_info_t + * + * \return Returns error code specified in \ref psa_status_t + */ +psa_status_t sfs_flash_fs_file_get_info(sfs_flash_fs_ctx_t *fs_ctx, + const uint8_t *fid, + struct sfs_file_info_t *info); + +/** + * \brief Writes data to an existing file. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] fid File ID + * \param[in] size Size of the incoming buffer + * \param[in] offset Offset in the file + * \param[in] data Pointer to buffer containing data to be written + * + * \return Returns error code as specified in \ref psa_status_t + */ +psa_status_t sfs_flash_fs_file_write(sfs_flash_fs_ctx_t *fs_ctx, + const uint8_t *fid, + size_t size, + size_t offset, + const uint8_t *data); + +/** + * \brief Reads data from an existing file. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] fid File ID + * \param[in] size Size to be read + * \param[in] offset Offset in the file + * \param[out] data Pointer to buffer to store the data + * + * \return Returns error code as specified in \ref psa_status_t + */ +psa_status_t sfs_flash_fs_file_read(sfs_flash_fs_ctx_t *fs_ctx, + const uint8_t *fid, + size_t size, + size_t offset, + uint8_t *data); + +/** + * \brief Deletes file referenced by the file ID. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] fid File ID + * + * \return Returns error code as specified in \ref psa_status_t + */ +psa_status_t sfs_flash_fs_file_delete(sfs_flash_fs_ctx_t *fs_ctx, + const uint8_t *fid); + +#ifdef __cplusplus +} +#endif + +#endif /* __SFS_FLASH_FS_H__ */ diff --git a/components/service/secure_storage/provider/secure_flash_store/flash_fs/sfs_flash_fs_check_info.h b/components/service/secure_storage/provider/secure_flash_store/flash_fs/sfs_flash_fs_check_info.h new file mode 100644 index 000000000..2ca2f101a --- /dev/null +++ b/components/service/secure_storage/provider/secure_flash_store/flash_fs/sfs_flash_fs_check_info.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2019-2020, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +/** + * \file sfs_flash_fs_check_info.h + * + * \brief Checks at compile time that the flash device configuration is valid. + * Should be included after defining the flash info parameters for a + * flash device. + */ + +#ifndef __SFS_FLASH_FS_CHECK_INFO_H__ +#define __SFS_FLASH_FS_CHECK_INFO_H__ + +#include "sfs_flash_fs_mblock.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SFS_BLOCK_META_HEADER_SIZE sizeof(struct sfs_metadata_block_header_t) +#define SFS_BLOCK_METADATA_SIZE sizeof(struct sfs_block_meta_t) +#define SFS_FILE_METADATA_SIZE sizeof(struct sfs_file_meta_t) + +#if ((FLASH_INFO_NUM_BLOCKS < 2) || (FLASH_INFO_NUM_BLOCKS == 3)) + /* The minimum number of blocks is 2. In this case, metadata and data are + * stored in the same physical block, and the other block is required for + * power failure safe operation. + * If at least 1 data block is available, 1 data scratch block is required for + * power failure safe operation. So, in this case, the minimum number of + * blocks is 4 (2 metadata block + 2 data blocks). + */ + #error "Total number of blocks should be 2 or bigger than 3" +#endif + +/* The numbers in the defines are physical block indexes, starting from 0, + * except for SFS_NUM_DEDICATED_DBLOCKS. + */ +#if (FLASH_INFO_NUM_BLOCKS == 2) + /* Metadata and data are stored in the same physical block, and the other + * block is required for power failure safe operation. + */ + + /* Initial position of scratch block is the scratch metadata block */ + #define SFS_INIT_SCRATCH_DBLOCK 1 + + /* Metadata and data are stored in the same block */ + #define SFS_INIT_DBLOCK_START 0 + + /* There are no dedicated data blocks when only two blocks are available */ + #define SFS_NUM_DEDICATED_DBLOCKS 0 + +#else + + /* Initial position of scratch block is immediately after metadata blocks */ + #define SFS_INIT_SCRATCH_DBLOCK 2 + + /* One metadata block and two scratch blocks are reserved. One scratch block + * for metadata operations and the other for files data operations. + */ + #define SFS_INIT_DBLOCK_START 3 + + /* Number of blocks dedicated just for data is the number of blocks available + * beyond the initial datablock start index. + */ + #define SFS_NUM_DEDICATED_DBLOCKS (FLASH_INFO_NUM_BLOCKS - \ + SFS_INIT_DBLOCK_START) +#endif /* FLASH_INFO_NUM_BLOCKS == 2 */ + +/* Total number of datablocks is the number of dedicated datablocks plus + * logical datablock 0 stored in the metadata block. + */ +#define SFS_NUM_ACTIVE_DBLOCKS (SFS_NUM_DEDICATED_DBLOCKS + 1) + +#define SFS_ALL_METADATA_SIZE \ + (SFS_BLOCK_META_HEADER_SIZE \ + + (SFS_NUM_ACTIVE_DBLOCKS * SFS_BLOCK_METADATA_SIZE) \ + + (FLASH_INFO_MAX_NUM_FILES * SFS_FILE_METADATA_SIZE)) + +/* It is not required that all files fit in SFS flash area at the same time. + * So, it is possible that a create action fails because flash is full. + * However, the larger file must have enough space in the SFS flash area to be + * created, at least, when the SFS flash area is empty. + */ +/* Checks at compile time if the largest file fits in the data area */ +SFS_UTILS_BOUND_CHECK(LARGEST_SFS_FILE_NOT_FIT_IN_DATA_BLOCK, + FLASH_INFO_MAX_FILE_SIZE, FLASH_INFO_BLOCK_SIZE); + +#if (FLASH_INFO_NUM_BLOCKS == 2) +SFS_UTILS_BOUND_CHECK(SFS_FILE_NOT_FIT_IN_DATA_AREA, FLASH_INFO_MAX_FILE_SIZE, + (FLASH_INFO_BLOCK_SIZE - SFS_ALL_METADATA_SIZE)); +#endif + +/* Checks at compile time if the metadata fits in a flash block */ +SFS_UTILS_BOUND_CHECK(SFS_METADATA_NOT_FIT_IN_METADATA_BLOCK, + SFS_ALL_METADATA_SIZE, FLASH_INFO_BLOCK_SIZE); + +#ifdef __cplusplus +} +#endif + +#endif /* __SFS_FLASH_FS_CHECK_INFO_H__ */ diff --git a/components/service/secure_storage/provider/secure_flash_store/flash_fs/sfs_flash_fs_dblock.c b/components/service/secure_storage/provider/secure_flash_store/flash_fs/sfs_flash_fs_dblock.c new file mode 100644 index 000000000..36dc33ae7 --- /dev/null +++ b/components/service/secure_storage/provider/secure_flash_store/flash_fs/sfs_flash_fs_dblock.c @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2018-2020, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include "sfs_flash_fs_dblock.h" + +#include "../flash/sfs_flash.h" + +/** + * \brief Converts logical data block number to physical number. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] lblock Logical block number + * + * \return Return physical block number. + */ +static uint32_t sfs_dblock_lo_to_phy(struct sfs_flash_fs_ctx_t *fs_ctx, + uint32_t lblock) +{ + struct sfs_block_meta_t block_meta; + int32_t err; + + err = sfs_flash_fs_mblock_read_block_metadata(fs_ctx, lblock, &block_meta); + if (err != PSA_SUCCESS) { + return SFS_BLOCK_INVALID_ID; + } + + return block_meta.phy_id; +} + +psa_status_t sfs_flash_fs_dblock_compact_block( + struct sfs_flash_fs_ctx_t *fs_ctx, + uint32_t lblock, + size_t free_size, + size_t src_offset, + size_t dst_offset, + size_t size) +{ + struct sfs_block_meta_t block_meta; + psa_status_t err; + uint32_t scratch_id = 0; + + /* Read current block meta */ + err = sfs_flash_fs_mblock_read_block_metadata(fs_ctx, lblock, &block_meta); + if (err != PSA_SUCCESS) { + return err; + } + + /* Release data from block meta */ + block_meta.free_size += free_size; + + /* Save scratch data block physical IDs */ + scratch_id = sfs_flash_fs_mblock_cur_data_scratch_id(fs_ctx, lblock); + + /* Check if there are bytes to be compacted */ + if (size > 0) { + /* Move data from source offset in current data block to scratch block + * destination offset. + */ + err = sfs_flash_block_to_block_move(fs_ctx->flash_info, scratch_id, + dst_offset, block_meta.phy_id, + src_offset, size); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + } + + if (dst_offset > block_meta.data_start) { + /* Copy data from the beginning of data block until + * the position where the data will be reallocated later + */ + err = sfs_flash_block_to_block_move(fs_ctx->flash_info, scratch_id, + block_meta.data_start, + block_meta.phy_id, + block_meta.data_start, + (dst_offset-block_meta.data_start)); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + } + + /* Swap the scratch and current data blocks. Must swap even with nothing + * to compact so that deleted file is left in scratch and erased as part + * of finalization. + */ + sfs_flash_fs_mblock_set_data_scratch(fs_ctx, block_meta.phy_id, lblock); + + /* Set scratch block ID as the one which contains the new data block */ + block_meta.phy_id = scratch_id; + + /* Update block metadata in scratch metadata block */ + err = sfs_flash_fs_mblock_update_scratch_block_meta(fs_ctx, lblock, + &block_meta); + if (err != PSA_SUCCESS) { + /* Swap back the data block as there was an issue in the process */ + sfs_flash_fs_mblock_set_data_scratch(fs_ctx, scratch_id, lblock); + return err; + } + + /* Commit data block modifications to flash, unless the data is in logical + * data block 0, in which case it will be flushed at the end of the metadata + * block update. + */ + if (lblock != SFS_LOGICAL_DBLOCK0) { + err = fs_ctx->flash_info->flush(fs_ctx->flash_info); + } + + return err; +} + +psa_status_t sfs_flash_fs_dblock_read_file( + struct sfs_flash_fs_ctx_t *fs_ctx, + const struct sfs_file_meta_t *file_meta, + size_t offset, + size_t size, + uint8_t *buf) +{ + uint32_t phys_block; + size_t pos; + + phys_block = sfs_dblock_lo_to_phy(fs_ctx, file_meta->lblock); + if (phys_block == SFS_BLOCK_INVALID_ID) { + return PSA_ERROR_GENERIC_ERROR; + } + + pos = (file_meta->data_idx + offset); + + return fs_ctx->flash_info->read(fs_ctx->flash_info, phys_block, buf, pos, + size); +} + +psa_status_t sfs_flash_fs_dblock_write_file( + struct sfs_flash_fs_ctx_t *fs_ctx, + const struct sfs_block_meta_t *block_meta, + const struct sfs_file_meta_t *file_meta, + size_t offset, + size_t size, + const uint8_t *data) +{ + psa_status_t err; + uint32_t scratch_id; + size_t pos; + size_t num_bytes; + + scratch_id = sfs_flash_fs_mblock_cur_data_scratch_id(fs_ctx, + file_meta->lblock); + + /* Calculate the position of the new file data in the block */ + pos = file_meta->data_idx + offset; + + /* Move data up to the new file data position */ + err = sfs_flash_block_to_block_move(fs_ctx->flash_info, + scratch_id, + block_meta->data_start, + block_meta->phy_id, + block_meta->data_start, + pos - block_meta->data_start); + if (err != PSA_SUCCESS) { + return err; + } + + /* Write the new file data */ + err = fs_ctx->flash_info->write(fs_ctx->flash_info, scratch_id, data, pos, + size); + if (err != PSA_SUCCESS) { + return err; + } + + /* Calculate the position of the end of the file */ + pos = file_meta->data_idx + file_meta->max_size; + + /* Calculate the size of the data in the block after the end of the file */ + num_bytes = (fs_ctx->flash_info->block_size - block_meta->free_size) - pos; + + /* Move data between the end of the file and the end of the block data */ + err = sfs_flash_block_to_block_move(fs_ctx->flash_info, scratch_id, pos, + block_meta->phy_id, pos, num_bytes); + if (err != PSA_SUCCESS) { + return err; + } + + /* Commit data block modifications to flash, unless the data is in logical + * data block 0, in which case it will be flushed at the end of the metadata + * block update. + */ + if (file_meta->lblock != SFS_LOGICAL_DBLOCK0) { + err = fs_ctx->flash_info->flush(fs_ctx->flash_info); + } + + return err; +} diff --git a/components/service/secure_storage/provider/secure_flash_store/flash_fs/sfs_flash_fs_dblock.h b/components/service/secure_storage/provider/secure_flash_store/flash_fs/sfs_flash_fs_dblock.h new file mode 100644 index 000000000..0fc9d50f4 --- /dev/null +++ b/components/service/secure_storage/provider/secure_flash_store/flash_fs/sfs_flash_fs_dblock.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2018-2020, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __SFS_FLASH_FS_DBLOCK_H__ +#define __SFS_FLASH_FS_DBLOCK_H__ + +#include <stddef.h> +#include <stdint.h> + +#include <protocols/service/psa/packed-c/status.h> +#include "sfs_flash_fs_mblock.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Compacts block data for the given logical block. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] lblock Logical data block to compact + * \param[in] free_size Available data size to compact + * \param[in] src_offset Offset in the current data block which points to + * the data position to reallocate + * \param[in] dst_offset Offset in the scratch block which points to the + * data position to store the data to be reallocated + * \param[in] size Number of bytes to be reallocated + * + * \return Returns error code as specified in \ref psa_status_t + */ +psa_status_t sfs_flash_fs_dblock_compact_block( + struct sfs_flash_fs_ctx_t *fs_ctx, + uint32_t lblock, + size_t free_size, + size_t src_offset, + size_t dst_offset, + size_t size); + +/** + * \brief Reads the file content. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] file_meta File metadata + * \param[in] offset Offset in the file + * \param[in] size Size to be read + * \param[out] buf Buffer pointer to store the data + * + * \return Returns error code as specified in \ref psa_status_t + */ +psa_status_t sfs_flash_fs_dblock_read_file( + struct sfs_flash_fs_ctx_t *fs_ctx, + const struct sfs_file_meta_t *file_meta, + size_t offset, + size_t size, + uint8_t *buf); + +/** + * \brief Writes scratch data block content with requested data and the rest of + * the data from the given logical block. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] block_meta Block metadata + * \param[in] file_meta File metadata + * \param[in] offset Offset in the scratch data block where to start + * the copy of the incoming data + * \param[in] size Size of the incoming data + * \param[in] data Pointer to data buffer to copy in the scratch data + * block + * + * \return Returns error code as specified in \ref psa_status_t + */ +psa_status_t sfs_flash_fs_dblock_write_file( + struct sfs_flash_fs_ctx_t *fs_ctx, + const struct sfs_block_meta_t *block_meta, + const struct sfs_file_meta_t *file_meta, + size_t offset, + size_t size, + const uint8_t *data); + +#ifdef __cplusplus +} +#endif + +#endif /* __SFS_FLASH_FS_DBLOCK_H__ */ diff --git a/components/service/secure_storage/provider/secure_flash_store/flash_fs/sfs_flash_fs_mblock.c b/components/service/secure_storage/provider/secure_flash_store/flash_fs/sfs_flash_fs_mblock.c new file mode 100644 index 000000000..cb435cf38 --- /dev/null +++ b/components/service/secure_storage/provider/secure_flash_store/flash_fs/sfs_flash_fs_mblock.c @@ -0,0 +1,1074 @@ +/* + * Copyright (c) 2018-2020, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include "sfs_flash_fs_mblock.h" +#include <string.h> + +/* Physical ID of the two metadata blocks */ +/* NOTE: the earmarked area may not always start at block number 0. + * However, the flash interface can always add the required offset. + */ +#define SFS_METADATA_BLOCK0 0 +#define SFS_METADATA_BLOCK1 1 + +/*! + * \def SFS_OTHER_META_BLOCK + * + * \brief Macro to get the the swap metadata block. + */ +#define SFS_OTHER_META_BLOCK(metablock) \ +(((metablock) == SFS_METADATA_BLOCK0) ? \ +(SFS_METADATA_BLOCK1) : (SFS_METADATA_BLOCK0)) + +#define SFS_BLOCK_META_HEADER_SIZE sizeof(struct sfs_metadata_block_header_t) +#define SFS_BLOCK_METADATA_SIZE sizeof(struct sfs_block_meta_t) +#define SFS_FILE_METADATA_SIZE sizeof(struct sfs_file_meta_t) + +/* FIXME: Precompute these for each context */ +/** + * \brief Gets the physical block ID of the initial position of the scratch + * data block, for the current context. + * + * \param[in,out] fs_ctx Filesystem context + * + * \return The physical block ID + */ +__attribute__((always_inline)) +static inline uint32_t sfs_init_scratch_dblock( + struct sfs_flash_fs_ctx_t *fs_ctx) +{ + /* When there are two blocks, the initial position of the scratch data block + * is the scratch metadata block. Otherwise, the initial position of scratch + * data block is immediately after the metadata blocks. + */ + return fs_ctx->flash_info->num_blocks == 2 ? 1 : 2; +} + +/** + * \brief Gets the physical block ID of the start position of the data blocks, + * for the current context. + * + * \param[in,out] fs_ctx Filesystem context + * + * \return The physical block ID + */ +__attribute__((always_inline)) +static inline uint32_t sfs_init_dblock_start(struct sfs_flash_fs_ctx_t *fs_ctx) +{ + /* Metadata and data are always stored in the same block with two blocks. + * Otherwise, one metadata block and two scratch blocks are reserved. One + * scratch block for metadata operations and the other for data operations. + */ + return fs_ctx->flash_info->num_blocks == 2 ? 0 : 3; +} + +/** + * \brief Gets the number of blocks that are dedicated wholely for data, for the + * current context. + * + * \param[in,out] fs_ctx Filesystem context + * + * \return The number of dedicated datablocks + */ +static uint32_t sfs_num_dedicated_dblocks(struct sfs_flash_fs_ctx_t *fs_ctx) +{ + /* There are no dedicated data blocks when only two blocks are available. + * Otherwise, the number of blocks dedicated just for data is the number of + * blocks available beyond the initial datablock start index. + */ + return fs_ctx->flash_info->num_blocks == 2 ? 0 : + fs_ctx->flash_info->num_blocks - sfs_init_dblock_start(fs_ctx); +} + +/** + * \brief Gets the number of active data blocks, for the current context. + * + * \param[in,out] fs_ctx Filesystem context + * + * \return The number of active datablocks + */ +__attribute__((always_inline)) +static inline uint32_t sfs_num_active_dblocks(struct sfs_flash_fs_ctx_t *fs_ctx) +{ + /* Total number of data blocks is the number of dedicated data blocks plus + * logical data block 0 stored in the metadata block. + */ + return sfs_num_dedicated_dblocks(fs_ctx) + 1; +} + +/** + * \brief Gets offset of a logical block's metadata in metadata block. + * + * \param[in] lblock Logical block number + * + * \return Return offset value in metadata block + */ +static size_t sfs_mblock_block_meta_offset(uint32_t lblock) +{ + return SFS_BLOCK_META_HEADER_SIZE + (lblock * SFS_BLOCK_METADATA_SIZE); +} + +/** + * \brief Gets offset of an file metadata in metadata block. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] idx File metadata entry index + * + * \return Return offset value in metadata block + */ +static size_t sfs_mblock_file_meta_offset(struct sfs_flash_fs_ctx_t *fs_ctx, + uint32_t idx) +{ + return SFS_BLOCK_META_HEADER_SIZE + + (sfs_num_active_dblocks(fs_ctx) * SFS_BLOCK_METADATA_SIZE) + + (idx * SFS_FILE_METADATA_SIZE); +} + +/** + * \brief Swaps metablocks. Scratch becomes active and active becomes scratch. + * + * \param[in,out] fs_ctx Filesystem context + */ +static void sfs_mblock_swap_metablocks(struct sfs_flash_fs_ctx_t *fs_ctx) +{ + uint32_t tmp_block; + + tmp_block = fs_ctx->scratch_metablock; + fs_ctx->scratch_metablock = fs_ctx->active_metablock; + fs_ctx->active_metablock = tmp_block; +} + +/** + * \brief Finds the potential most recent valid metablock. + * + * \param[in] h_meta0 Header metadata of meta block 0 + * \param[in] h_meta1 Header metadata of meta block 1 + * + * \return most recent metablock + */ +static uint8_t sfs_mblock_latest_meta_block( + const struct sfs_metadata_block_header_t *h_meta0, + const struct sfs_metadata_block_header_t *h_meta1) +{ + uint8_t cur_meta; + uint8_t meta0_swap_count = h_meta0->active_swap_count; + uint8_t meta1_swap_count = h_meta1->active_swap_count; + + /* Logic: if the swap count is 0, then it has rolled over. The metadata + * block with a swap count of 0 is the latest one, unless the other block + * has a swap count of 1, in which case the roll over occurred in the + * previous update. In all other cases, the block with the highest swap + * count is the latest one. + */ + if ((meta1_swap_count == 0) && (meta0_swap_count != 1)) { + /* Metadata block 1 swap count has rolled over and metadata block 0 + * swap count has not, so block 1 is the latest. + */ + cur_meta = SFS_METADATA_BLOCK1; + + } else if ((meta0_swap_count == 0) && (meta1_swap_count != 1)) { + /* Metadata block 0 swap count has rolled over and metadata block 1 + * swap count has not, so block 0 is the latest. + */ + cur_meta = SFS_METADATA_BLOCK0; + + } else if (meta1_swap_count > meta0_swap_count) { + /* Neither swap count has just rolled over and metadata block 1 has a + * higher swap count, so block 1 is the latest. + */ + cur_meta = SFS_METADATA_BLOCK1; + + } else { + /* Neither swap count has just rolled over and metadata block 0 has a + * higher or equal swap count, so block 0 is the latest. + */ + cur_meta = SFS_METADATA_BLOCK0; + } + + return cur_meta; +} + +#ifdef SFS_VALIDATE_METADATA_FROM_FLASH +/** + * \brief Validates file metadata in order to guarantee that a corruption or + * malicious change in stored metadata doesn't result in an invalid + * access. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] file_meta Pointer to file meta structure + * + * \return Returns error code as specified in \ref psa_status_t + */ +__attribute__((always_inline)) +static inline psa_status_t sfs_mblock_validate_file_meta( + struct sfs_flash_fs_ctx_t *fs_ctx, + const struct sfs_file_meta_t *file_meta) +{ + int32_t err; + + /* Logical block ID can not be bigger or equal than number of + * active blocks. + */ + if (file_meta->lblock >= sfs_num_active_dblocks(fs_ctx)) { + return PSA_ERROR_DATA_CORRUPT; + } + + /* meta->id can be 0 if the file is not in use. If it is in + * use, check the metadata. + */ + if (sfs_utils_validate_fid(file_meta->id) == PSA_SUCCESS) { + /* validate files values if file is in use */ + if (file_meta->max_size > fs_ctx->flash_info->max_file_size) { + return PSA_ERROR_DATA_CORRUPT; + } + + /* The current file data size must be smaller or equal than + * file data max size. + */ + if (file_meta->cur_size > file_meta->max_size) { + return PSA_ERROR_DATA_CORRUPT; + } + + if (file_meta->lblock == SFS_LOGICAL_DBLOCK0) { + /* In block 0, data index must be located after the metadata */ + if (file_meta->data_idx < sfs_mblock_file_meta_offset(fs_ctx, + fs_ctx->flash_info->max_num_files)) { + return PSA_ERROR_DATA_CORRUPT; + } + } + + /* Boundary check the incoming request */ + err = sfs_utils_check_contained_in(fs_ctx->flash_info->block_size, + file_meta->data_idx, + file_meta->max_size); + if (err != PSA_SUCCESS) { + return PSA_ERROR_DATA_CORRUPT; + } + } + + return PSA_SUCCESS; +} + +/** + * \brief Validates block metadata in order to guarantee that a corruption or + * malicious change in stored metadata doesn't result in an invalid + * access. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] block_meta Pointer to block meta structure + * + * \return Returns error code as specified in \ref psa_status_t + */ +__attribute__((always_inline)) +static inline psa_status_t sfs_mblock_validate_block_meta( + struct sfs_flash_fs_ctx_t *fs_ctx, + const struct sfs_block_meta_t *block_meta) +{ + psa_status_t err; + /* Data block's data start at position 0 */ + size_t valid_data_start_value = 0; + + if (block_meta->phy_id >= fs_ctx->flash_info->num_blocks) { + return PSA_ERROR_DATA_CORRUPT; + } + + /* Boundary check: block data start + free size can not be bigger + * than max block size. + */ + err = sfs_utils_check_contained_in(fs_ctx->flash_info->block_size, + block_meta->data_start, + block_meta->free_size); + if (err != PSA_SUCCESS) { + return PSA_ERROR_DATA_CORRUPT; + } + + if (block_meta->phy_id == SFS_METADATA_BLOCK0 || + block_meta->phy_id == SFS_METADATA_BLOCK1) { + + /* For metadata + data block, data index must start after the + * metadata area. + */ + valid_data_start_value = sfs_mblock_file_meta_offset(fs_ctx, + fs_ctx->flash_info->max_num_files); + } + + if (block_meta->data_start != valid_data_start_value) { + return PSA_ERROR_DATA_CORRUPT; + } + + return PSA_SUCCESS; +} +#endif /* SFS_VALIDATE_METADATA_FROM_FLASH */ + +/** + * \brief Gets a free file metadata table entry. + * + * \param[in,out] fs_ctx Filesystem context + * + * \return Return index of a free file meta entry + */ +static uint32_t sfs_get_free_file_index(struct sfs_flash_fs_ctx_t *fs_ctx) +{ + int32_t err; + uint32_t i; + struct sfs_file_meta_t tmp_metadata; + + for (i = 0; i < fs_ctx->flash_info->max_num_files; i++) { + err = sfs_flash_fs_mblock_read_file_meta(fs_ctx, i, &tmp_metadata); + if (err != PSA_SUCCESS) { + return SFS_METADATA_INVALID_INDEX; + } + + /* Check if this entry is free by checking if ID values is an + * invalid ID. + */ + if (sfs_utils_validate_fid(tmp_metadata.id) != PSA_SUCCESS) { + /* Found */ + return i; + } + } + + return SFS_METADATA_INVALID_INDEX; +} + +/** + * \brief Erases data and meta scratch blocks. + * + * \param[in,out] fs_ctx Filesystem context + * + * \return Returns error code as specified in \ref psa_status_t + */ +static psa_status_t sfs_mblock_erase_scratch_blocks( + struct sfs_flash_fs_ctx_t *fs_ctx) +{ + psa_status_t err; + uint32_t scratch_datablock; + + /* For the atomicity of the data update process + * and power-failure-safe operation, it is necessary that + * metadata scratch block is erased before data block. + */ + err = fs_ctx->flash_info->erase(fs_ctx->flash_info, + fs_ctx->scratch_metablock); + if (err != PSA_SUCCESS) { + return err; + } + + /* If the number of blocks is bigger than 2, the code needs to erase the + * scratch block used to process any change in the data block which contains + * only data. Otherwise, if the number of blocks is equal to 2, it means + * that all data is stored in the metadata block. + */ + if (fs_ctx->flash_info->num_blocks > 2) { + scratch_datablock = + sfs_flash_fs_mblock_cur_data_scratch_id(fs_ctx, + (SFS_LOGICAL_DBLOCK0 + 1)); + err = fs_ctx->flash_info->erase(fs_ctx->flash_info, scratch_datablock); + } + + return err; +} + +/** + * \brief Updates scratch block meta. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] lblock Logical block number + * \param[in] block_meta Pointer to the block metadata data to write in the + * scratch block + * + * \return Returns error code as specified in \ref psa_status_t + */ +static psa_status_t sfs_mblock_update_scratch_block_meta( + struct sfs_flash_fs_ctx_t *fs_ctx, + uint32_t lblock, + const struct sfs_block_meta_t *block_meta) +{ + size_t pos; + + /* Calculate the position */ + pos = sfs_mblock_block_meta_offset(lblock); + return fs_ctx->flash_info->write(fs_ctx->flash_info, + fs_ctx->scratch_metablock, + (const uint8_t *)block_meta, pos, + SFS_BLOCK_METADATA_SIZE); +} + +/** + * \brief Copies rest of the block metadata. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] lblock Logical block number to skip + * + * \return Returns error code as specified in \ref psa_status_t + */ +static psa_status_t sfs_mblock_copy_remaining_block_meta( + struct sfs_flash_fs_ctx_t *fs_ctx, + uint32_t lblock) +{ + struct sfs_block_meta_t block_meta; + psa_status_t err; + uint32_t meta_block; + size_t pos; + uint32_t scratch_block; + size_t size; + + scratch_block = fs_ctx->scratch_metablock; + meta_block = fs_ctx->active_metablock; + + if (lblock != SFS_LOGICAL_DBLOCK0) { + /* The file data in the logical block 0 is stored in same physical + * block where the metadata is stored. A change in the metadata requires + * a swap of physical blocks. So, the physical block ID of logical block + * 0 needs to be updated to reflect this change, if the file processed + * is not located in logical block 0. If it is located in block 0, + * the physical block ID has been updated while processing the file + * data. + */ + err = sfs_flash_fs_mblock_read_block_metadata(fs_ctx, + SFS_LOGICAL_DBLOCK0, + &block_meta); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + + /* Update physical ID for logical block 0 to match with the + * metadata block physical ID. + */ + block_meta.phy_id = scratch_block; + err = sfs_mblock_update_scratch_block_meta(fs_ctx, SFS_LOGICAL_DBLOCK0, + &block_meta); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + + /* Copy the rest of metadata blocks between logical block 0 and + * the logical block provided in the function. + */ + if (lblock > 1) { + pos = sfs_mblock_block_meta_offset(SFS_LOGICAL_DBLOCK0 + 1); + + size = sfs_mblock_block_meta_offset(lblock) - pos; + + /* Copy rest of the block data from previous block */ + /* Data before updated content */ + err = sfs_flash_block_to_block_move(fs_ctx->flash_info, + scratch_block, pos, meta_block, + pos, size); + if (err != PSA_SUCCESS) { + return err; + } + } + } + + /* Move meta blocks data after updated content */ + pos = sfs_mblock_block_meta_offset(lblock+1); + + size = sfs_mblock_file_meta_offset(fs_ctx, 0) - pos; + + return sfs_flash_block_to_block_move(fs_ctx->flash_info, scratch_block, pos, + meta_block, pos, size); +} + +/** + * \brief Checks the validity of the metadata block's swap count. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] swap_count Swap count to validate + * + * \return Returns error code as specified in \ref psa_status_t + */ +__attribute__((always_inline)) +static inline psa_status_t sfs_mblock_validate_swap_count( + struct sfs_flash_fs_ctx_t *fs_ctx, + uint8_t swap_count) +{ + /* When a flash block is erased, the default value + * is usually 0xFF (i.e. all 1s). Since the swap count + * is updated last (when encryption is disabled), it is + * possible that due to a power failure, the swap count + * value in metadata header is 0xFFFF..., which mean + * it will appear to be most recent block. Which isn't + * a problem in itself, as the rest of the metadata is fully + * valid (as it would have been written before swap count). + * However, this also means that previous update process + * wasn't complete. So, if the value is 0xFF..., revert + * back to previous metablock instead. + */ + return (swap_count == fs_ctx->flash_info->erase_val) + ? PSA_ERROR_GENERIC_ERROR + : PSA_SUCCESS; +} + +/** + * \brief Checks the validity of FS version. + * + * \param[in] fs_version File system version. + * + * \return Returns error code as specified in \ref psa_status_t + */ +__attribute__((always_inline)) +static inline psa_status_t sfs_mblock_validate_fs_version(uint8_t fs_version) +{ + /* Looks for exact version number. + * FIXME: backward compatibility could be considered in future revisions. + */ + return (fs_version != SFS_SUPPORTED_VERSION) ? PSA_ERROR_GENERIC_ERROR + : PSA_SUCCESS; +} + +/** + * \brief Validates header metadata in order to guarantee that a corruption or + * malicious change in stored metadata doesn't result in an invalid + * access and the header version is correct. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] h_meta Pointer to metadata block header + * + * \return Returns error code as specified in \ref psa_status_t + */ +static psa_status_t sfs_mblock_validate_header_meta( + struct sfs_flash_fs_ctx_t *fs_ctx, + const struct sfs_metadata_block_header_t *h_meta) +{ + psa_status_t err; + + err = sfs_mblock_validate_fs_version(h_meta->fs_version); + if (err == PSA_SUCCESS) { + err = sfs_mblock_validate_swap_count(fs_ctx, h_meta->active_swap_count); + } + + return err; +} + +/** + * \brief Writes the scratch metadata's header. + * + * \param[in,out] fs_ctx Filesystem context + * + * \return Returns error code as specified in \ref psa_status_t + */ +static psa_status_t sfs_mblock_write_scratch_meta_header( + struct sfs_flash_fs_ctx_t *fs_ctx) +{ + psa_status_t err; + + /* Increment the swap count */ + fs_ctx->meta_block_header.active_swap_count += 1; + + err = sfs_mblock_validate_swap_count(fs_ctx, + fs_ctx->meta_block_header.active_swap_count); + if (err != PSA_SUCCESS) { + /* Reset the swap count to 0 */ + fs_ctx->meta_block_header.active_swap_count = 0; + } + + /* Write the metadata block header */ + return fs_ctx->flash_info->write(fs_ctx->flash_info, + fs_ctx->scratch_metablock, + (uint8_t *)(&fs_ctx->meta_block_header), + 0, SFS_BLOCK_META_HEADER_SIZE); +} + +/** + * \brief Reads the active metadata block header into sfs_system_ctx. + * + * \param[in,out] fs_ctx Filesystem context + * + * \return Returns error code as specified in \ref psa_status_t + */ +static psa_status_t sfs_mblock_read_meta_header( + struct sfs_flash_fs_ctx_t *fs_ctx) +{ + psa_status_t err; + + err = fs_ctx->flash_info->read(fs_ctx->flash_info, fs_ctx->active_metablock, + (uint8_t *)&fs_ctx->meta_block_header, 0, + SFS_BLOCK_META_HEADER_SIZE); + if (err != PSA_SUCCESS) { + return err; + } + + return sfs_mblock_validate_header_meta(fs_ctx, &fs_ctx->meta_block_header); +} + +/** + * \brief Reserves space for an file. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] fid File ID + * \param[in] size Size of the file for which space is reserve + * \param[in] flags Flags set when the file is created + * \param[out] file_meta File metadata entry + * \param[out] block_meta Block metadata entry + * + * \return Returns error code as specified in \ref psa_status_t + */ +static psa_status_t sfs_mblock_reserve_file(struct sfs_flash_fs_ctx_t *fs_ctx, + const uint8_t *fid, size_t size, + uint32_t flags, + struct sfs_file_meta_t *file_meta, + struct sfs_block_meta_t *block_meta) +{ + psa_status_t err; + uint32_t i; + + for (i = 0; i < sfs_num_active_dblocks(fs_ctx); i++) { + err = sfs_flash_fs_mblock_read_block_metadata(fs_ctx, i, block_meta); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + + if (block_meta->free_size >= size) { + /* Set file metadata */ + file_meta->lblock = i; + file_meta->data_idx = fs_ctx->flash_info->block_size + - block_meta->free_size; + file_meta->max_size = size; + memcpy(file_meta->id, fid, SFS_FILE_ID_SIZE); + file_meta->cur_size = 0; + file_meta->flags = flags; + + /* Update block metadata */ + block_meta->free_size -= size; + return PSA_SUCCESS; + } + } + + /* No block has large enough space to fit the requested file */ + return PSA_ERROR_INSUFFICIENT_STORAGE; +} + +/** + * \brief Validates and find the valid-active metablock + * + * \param[in,out] fs_ctx Filesystem context + * + * \return Returns value as specified in \ref psa_status_t + */ +static psa_status_t sfs_init_get_active_metablock( + struct sfs_flash_fs_ctx_t *fs_ctx) +{ + uint32_t cur_meta_block = SFS_BLOCK_INVALID_ID; + psa_status_t err; + struct sfs_metadata_block_header_t h_meta0; + struct sfs_metadata_block_header_t h_meta1; + uint8_t num_valid_meta_blocks = 0; + + /* First two blocks are reserved for metadata */ + + /* Read the header of both the metdata blocks. If the read succeeds, then + * attempt to validate the metadata header, otherwise assume that the block + * update was incomplete + */ + err = fs_ctx->flash_info->read(fs_ctx->flash_info, SFS_METADATA_BLOCK0, + (uint8_t *)&h_meta0, 0, + SFS_BLOCK_META_HEADER_SIZE); + if (err == PSA_SUCCESS) { + if (sfs_mblock_validate_header_meta(fs_ctx, &h_meta0) == PSA_SUCCESS) { + num_valid_meta_blocks++; + cur_meta_block = SFS_METADATA_BLOCK0; + } + } + + err = fs_ctx->flash_info->read(fs_ctx->flash_info, SFS_METADATA_BLOCK1, + (uint8_t *)&h_meta1, 0, + SFS_BLOCK_META_HEADER_SIZE); + if (err == PSA_SUCCESS) { + if (sfs_mblock_validate_header_meta(fs_ctx, &h_meta1) == PSA_SUCCESS) { + num_valid_meta_blocks++; + cur_meta_block = SFS_METADATA_BLOCK1; + } + } + + /* If there are more than 1 potential metablocks, the previous + * update operation was interrupted by power failure. In which case, + * need to find out which one is potentially latest metablock. + */ + if (num_valid_meta_blocks > 1) { + cur_meta_block = sfs_mblock_latest_meta_block(&h_meta0, &h_meta1); + } else if (num_valid_meta_blocks == 0) { + return PSA_ERROR_GENERIC_ERROR; + } + + fs_ctx->active_metablock = cur_meta_block; + fs_ctx->scratch_metablock = SFS_OTHER_META_BLOCK(cur_meta_block); + + return PSA_SUCCESS; +} + +psa_status_t sfs_flash_fs_mblock_cp_remaining_file_meta( + struct sfs_flash_fs_ctx_t *fs_ctx, + uint32_t idx) +{ + psa_status_t err; + size_t end; + uint32_t meta_block; + size_t pos; + uint32_t scratch_block; + + scratch_block = fs_ctx->scratch_metablock; + meta_block = fs_ctx->active_metablock; + /* Calculate the position */ + pos = sfs_mblock_file_meta_offset(fs_ctx, 0); + /* Copy rest of the block data from previous block */ + /* Data before updated content */ + err = sfs_flash_block_to_block_move(fs_ctx->flash_info, scratch_block, pos, + meta_block, pos, + (idx * SFS_FILE_METADATA_SIZE)); + if (err != PSA_SUCCESS) { + return err; + } + + /* Data after updated content */ + pos = sfs_mblock_file_meta_offset(fs_ctx, idx + 1); + + /* Get end of file meta position which is the position after the last + * byte of file meta. + */ + end = sfs_mblock_file_meta_offset(fs_ctx, + fs_ctx->flash_info->max_num_files); + if (end > pos) { + err = sfs_flash_block_to_block_move(fs_ctx->flash_info, scratch_block, + pos, meta_block, pos, (end - pos)); + } + + return err; +} + +uint32_t sfs_flash_fs_mblock_cur_data_scratch_id( + struct sfs_flash_fs_ctx_t *fs_ctx, + uint32_t lblock) +{ + if (lblock == SFS_LOGICAL_DBLOCK0) { + /* Scratch logical data block 0 physical IDs */ + return fs_ctx->scratch_metablock; + } + + return fs_ctx->meta_block_header.scratch_dblock; +} + +psa_status_t sfs_flash_fs_mblock_get_file_idx(struct sfs_flash_fs_ctx_t *fs_ctx, + const uint8_t *fid, + uint32_t *idx) +{ + psa_status_t err; + uint32_t i; + struct sfs_file_meta_t tmp_metadata; + + for (i = 0; i < fs_ctx->flash_info->max_num_files; i++) { + err = sfs_flash_fs_mblock_read_file_meta(fs_ctx, i, &tmp_metadata); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + + /* ID with value 0x00 means end of file meta section */ + if (!memcmp(tmp_metadata.id, fid, SFS_FILE_ID_SIZE)) { + /* Found */ + *idx = i; + return PSA_SUCCESS; + } + } + + return PSA_ERROR_DOES_NOT_EXIST; +} + +psa_status_t sfs_flash_fs_mblock_init(struct sfs_flash_fs_ctx_t *fs_ctx) +{ + psa_status_t err; + + /* Initialize Flash Interface */ + err = fs_ctx->flash_info->init(fs_ctx->flash_info); + if (err != PSA_SUCCESS) { + return err; + } + + err = sfs_init_get_active_metablock(fs_ctx); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + + err = sfs_mblock_read_meta_header(fs_ctx); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + + /* Erase the other scratch metadata block */ + return sfs_mblock_erase_scratch_blocks(fs_ctx); +} + +psa_status_t sfs_flash_fs_mblock_meta_update_finalize( + struct sfs_flash_fs_ctx_t *fs_ctx) +{ + psa_status_t err; + + /* Write the metadata block header to flash */ + err = sfs_mblock_write_scratch_meta_header(fs_ctx); + if (err != PSA_SUCCESS) { + return err; + } + + /* Commit metadata block modifications to flash */ + err = fs_ctx->flash_info->flush(fs_ctx->flash_info); + if (err != PSA_SUCCESS) { + return err; + } + + /* Update the running context */ + sfs_mblock_swap_metablocks(fs_ctx); + + /* Erase meta block and current scratch block */ + return sfs_mblock_erase_scratch_blocks(fs_ctx); +} + +psa_status_t sfs_flash_fs_mblock_migrate_lb0_data_to_scratch( + struct sfs_flash_fs_ctx_t *fs_ctx) +{ + struct sfs_block_meta_t block_meta; + size_t data_size; + psa_status_t err; + + err = sfs_flash_fs_mblock_read_block_metadata(fs_ctx, SFS_LOGICAL_DBLOCK0, + &block_meta); + if (err != PSA_SUCCESS) { + return err; + } + + /* Calculate data size stored in the B0 block */ + data_size = (fs_ctx->flash_info->block_size - block_meta.data_start) + - block_meta.free_size; + + return sfs_flash_block_to_block_move(fs_ctx->flash_info, + fs_ctx->scratch_metablock, + block_meta.data_start, + fs_ctx->active_metablock, + block_meta.data_start, + data_size); +} + +psa_status_t sfs_flash_fs_mblock_read_file_meta( + struct sfs_flash_fs_ctx_t *fs_ctx, + uint32_t idx, + struct sfs_file_meta_t *file_meta) +{ + psa_status_t err; + size_t offset; + + offset = sfs_mblock_file_meta_offset(fs_ctx, idx); + err = fs_ctx->flash_info->read(fs_ctx->flash_info, fs_ctx->active_metablock, + (uint8_t *)file_meta, offset, + SFS_FILE_METADATA_SIZE); + +#ifdef SFS_VALIDATE_METADATA_FROM_FLASH + if (err == PSA_SUCCESS) { + err = sfs_mblock_validate_file_meta(fs_ctx, file_meta); + } +#endif + + return err; +} + +psa_status_t sfs_flash_fs_mblock_read_block_metadata( + struct sfs_flash_fs_ctx_t *fs_ctx, + uint32_t lblock, + struct sfs_block_meta_t *block_meta) +{ + psa_status_t err; + size_t pos; + + pos = sfs_mblock_block_meta_offset(lblock); + err = fs_ctx->flash_info->read(fs_ctx->flash_info, fs_ctx->active_metablock, + (uint8_t *)block_meta, pos, + SFS_BLOCK_METADATA_SIZE); + +#ifdef SFS_VALIDATE_METADATA_FROM_FLASH + if (err == PSA_SUCCESS) { + err = sfs_mblock_validate_block_meta(fs_ctx, block_meta); + } +#endif + + return err; +} + +psa_status_t sfs_flash_fs_mblock_reserve_file( + struct sfs_flash_fs_ctx_t *fs_ctx, + const uint8_t *fid, + size_t size, + uint32_t flags, + uint32_t *idx, + struct sfs_file_meta_t *file_meta, + struct sfs_block_meta_t *block_meta) +{ + psa_status_t err; + + err = sfs_mblock_reserve_file(fs_ctx, fid, size, flags, file_meta, + block_meta); + + *idx = sfs_get_free_file_index(fs_ctx); + if ((err != PSA_SUCCESS) || + (*idx == SFS_METADATA_INVALID_INDEX)) { + return PSA_ERROR_INSUFFICIENT_STORAGE; + } + + return PSA_SUCCESS; +} + +psa_status_t sfs_flash_fs_mblock_reset_metablock( + struct sfs_flash_fs_ctx_t *fs_ctx) +{ + struct sfs_block_meta_t block_meta; + psa_status_t err; + uint32_t i; + uint32_t metablock_to_erase_first = SFS_METADATA_BLOCK0; + struct sfs_file_meta_t file_metadata; + + /* Erase both metadata blocks. If at least one metadata block is valid, + * ensure that the active metadata block is erased last to prevent rollback + * in the case of a power failure between the two erases. + */ + if (sfs_init_get_active_metablock(fs_ctx) == PSA_SUCCESS) { + metablock_to_erase_first = fs_ctx->scratch_metablock; + } + + err = fs_ctx->flash_info->erase(fs_ctx->flash_info, + metablock_to_erase_first); + if (err != PSA_SUCCESS) { + return err; + } + + err = fs_ctx->flash_info->erase(fs_ctx->flash_info, + SFS_OTHER_META_BLOCK(metablock_to_erase_first)); + if (err != PSA_SUCCESS) { + return err; + } + + fs_ctx->meta_block_header.active_swap_count = 0; + fs_ctx->meta_block_header.scratch_dblock = sfs_init_scratch_dblock(fs_ctx); + fs_ctx->meta_block_header.fs_version = SFS_SUPPORTED_VERSION; + fs_ctx->scratch_metablock = SFS_METADATA_BLOCK1; + fs_ctx->active_metablock = SFS_METADATA_BLOCK0; + + /* Fill the block metadata for logical datablock 0, which has the physical + * id of the active metadata block. For this datablock, the space available + * for data is from the end of the metadata to the end of the block. + */ + block_meta.data_start = + sfs_mblock_file_meta_offset(fs_ctx, fs_ctx->flash_info->max_num_files); + block_meta.free_size = fs_ctx->flash_info->block_size + - block_meta.data_start; + block_meta.phy_id = SFS_METADATA_BLOCK0; + err = sfs_mblock_update_scratch_block_meta(fs_ctx, SFS_LOGICAL_DBLOCK0, + &block_meta); + if (err != PSA_SUCCESS) { + return err; + } + + /* Fill the block metadata for the dedicated datablocks, which have logical + * ids beginning from 1 and physical ids initially beginning from + * SFS_INIT_DBLOCK_START. For these datablocks, the space available for + * data is the entire block. + */ + block_meta.data_start = 0; + block_meta.free_size = fs_ctx->flash_info->block_size; + for (i = 0; i < sfs_num_dedicated_dblocks(fs_ctx); i++) { + /* If a flash error is detected, the code erases the rest + * of the blocks anyway to remove all data stored in them. + */ + err |= fs_ctx->flash_info->erase(fs_ctx->flash_info, + i + sfs_init_dblock_start(fs_ctx)); + } + + /* If an error is detected while erasing the flash, then return a + * system error to abort core wipe process. + */ + if (err != PSA_SUCCESS) { + return PSA_ERROR_STORAGE_FAILURE; + } + + for (i = 0; i < sfs_num_dedicated_dblocks(fs_ctx); i++) { + block_meta.phy_id = i + sfs_init_dblock_start(fs_ctx); + err = sfs_mblock_update_scratch_block_meta(fs_ctx, i + 1, &block_meta); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + } + + /* Initialize file metadata table */ + (void)memset(&file_metadata, SFS_DEFAULT_EMPTY_BUFF_VAL, + SFS_FILE_METADATA_SIZE); + for (i = 0; i < fs_ctx->flash_info->max_num_files; i++) { + /* In the beginning phys id is same as logical id */ + /* Update file metadata to reflect new attributes */ + err = sfs_flash_fs_mblock_update_scratch_file_meta(fs_ctx, i, + &file_metadata); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + } + + err = sfs_mblock_write_scratch_meta_header(fs_ctx); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + + /* Commit metadata block modifications to flash */ + err = fs_ctx->flash_info->flush(fs_ctx->flash_info); + if (err != PSA_SUCCESS) { + return err; + } + + /* Swap active and scratch metablocks */ + sfs_mblock_swap_metablocks(fs_ctx); + + return PSA_SUCCESS; +} + +void sfs_flash_fs_mblock_set_data_scratch(struct sfs_flash_fs_ctx_t *fs_ctx, + uint32_t phy_id, uint32_t lblock) +{ + if (lblock != SFS_LOGICAL_DBLOCK0) { + fs_ctx->meta_block_header.scratch_dblock = phy_id; + } +} + +psa_status_t sfs_flash_fs_mblock_update_scratch_block_meta( + struct sfs_flash_fs_ctx_t *fs_ctx, + uint32_t lblock, + struct sfs_block_meta_t *block_meta) +{ + psa_status_t err; + + /* If the file is the logical block 0, then update the physical ID to the + * current scratch metadata block so that it is correct after the metadata + * blocks are swapped. + */ + if (lblock == SFS_LOGICAL_DBLOCK0) { + block_meta->phy_id = fs_ctx->scratch_metablock; + } + + err = sfs_mblock_update_scratch_block_meta(fs_ctx, lblock, block_meta); + if (err != PSA_SUCCESS) { + return PSA_ERROR_GENERIC_ERROR; + } + + return sfs_mblock_copy_remaining_block_meta(fs_ctx, lblock); +} + +psa_status_t sfs_flash_fs_mblock_update_scratch_file_meta( + struct sfs_flash_fs_ctx_t *fs_ctx, + uint32_t idx, + const struct sfs_file_meta_t *file_meta) +{ + size_t pos; + + /* Calculate the position */ + pos = sfs_mblock_file_meta_offset(fs_ctx, idx); + return fs_ctx->flash_info->write(fs_ctx->flash_info, + fs_ctx->scratch_metablock, + (const uint8_t *)file_meta, pos, + SFS_FILE_METADATA_SIZE); +} diff --git a/components/service/secure_storage/provider/secure_flash_store/flash_fs/sfs_flash_fs_mblock.h b/components/service/secure_storage/provider/secure_flash_store/flash_fs/sfs_flash_fs_mblock.h new file mode 100644 index 000000000..d13a5b0db --- /dev/null +++ b/components/service/secure_storage/provider/secure_flash_store/flash_fs/sfs_flash_fs_mblock.h @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2018-2020, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __SFS_FLASH_FS_MBLOCK_H__ +#define __SFS_FLASH_FS_MBLOCK_H__ + +#include <stddef.h> +#include <stdint.h> + +#include "../flash/sfs_flash.h" +#include "../sfs_utils.h" +#include <protocols/service/psa/packed-c/status.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \def SFS_SUPPORTED_VERSION + * + * \brief Defines the supported version. + */ +#define SFS_SUPPORTED_VERSION 0x01 + +/*! + * \def SFS_METADATA_INVALID_INDEX + * + * \brief Defines the invalid index value when the metadata table is full + */ +#define SFS_METADATA_INVALID_INDEX 0xFFFF + +/*! + * \def SFS_LOGICAL_DBLOCK0 + * + * \brief Defines logical data block 0 ID + */ +#define SFS_LOGICAL_DBLOCK0 0 + +/*! + * \struct sfs_metadata_block_header_t + * + * \brief Structure to store the metadata block header. + * + * \note The active_swap_count must be the last member to allow it to be + * programmed last. + * + * \note This structure is programmed to flash, so it must be aligned to the + * maximum required flash program unit. + */ +struct __attribute__((__aligned__(SFS_FLASH_MAX_ALIGNMENT))) +sfs_metadata_block_header_t { + uint32_t scratch_dblock; /*!< Physical block ID of the data + * section's scratch block + */ + uint8_t fs_version; /*!< SFS system version */ + uint8_t active_swap_count; /*!< Physical block ID of the data */ +}; + +/*! + * \struct sfs_block_meta_t + * + * \brief Structure to store information about each physical flash memory block. + * + * \note This structure is programmed to flash, so it must be aligned to the + * maximum required flash program unit. + */ +struct __attribute__((__aligned__(SFS_FLASH_MAX_ALIGNMENT))) +sfs_block_meta_t { + uint32_t phy_id; /*!< Physical ID of this logical block */ + size_t data_start; /*!< Offset from the beginning of the block to the + * location where the data starts + */ + size_t free_size; /*!< Number of bytes free at end of block (set during + * block compaction for gap reuse) + */ +}; + +/*! + * \struct sfs_file_meta_t + * + * \brief Structure to store file metadata. + * + * \note This structure is programmed to flash, so it must be aligned to the + * maximum required flash program unit. + */ +struct __attribute__((__aligned__(SFS_FLASH_MAX_ALIGNMENT))) +sfs_file_meta_t { + uint32_t lblock; /*!< Logical datablock where file is + * stored + */ + size_t data_idx; /*!< Offset in the logical data block */ + size_t cur_size; /*!< Size in storage system for this # + * fragment + */ + size_t max_size; /*!< Maximum size of this file */ + uint32_t flags; /*!< Flags set when the file was created */ + uint8_t id[SFS_FILE_ID_SIZE]; /*!< ID of this file */ +}; + +/** + * \struct sfs_flash_fs_ctx_t + * + * \brief Structure to store the SFS flash file system context. + */ +struct sfs_flash_fs_ctx_t { + const struct sfs_flash_info_t *flash_info; /**< Info for the flash device */ + struct sfs_metadata_block_header_t meta_block_header; /**< Metadata block + * header + */ + uint32_t active_metablock; /**< Active metadata block */ + uint32_t scratch_metablock; /**< Scratch metadata block */ +}; + +/** + * \brief Initializes metadata block with the valid/active metablock. + * + * \param[in,out] fs_ctx Filesystem context + * + * \return Returns value as specified in \ref psa_status_t + */ +psa_status_t sfs_flash_fs_mblock_init(struct sfs_flash_fs_ctx_t *fs_ctx); + +/** + * \brief Copies rest of the file metadata, except for the one pointed by + * index. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] idx File metadata entry index to skip + * + * \return Returns error code as specified in \ref psa_status_t + */ +psa_status_t sfs_flash_fs_mblock_cp_remaining_file_meta( + struct sfs_flash_fs_ctx_t *fs_ctx, + uint32_t idx); + +/** + * \brief Gets current scratch datablock physical ID. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] lblock Logical block number + * + * \return current scratch data block + */ +uint32_t sfs_flash_fs_mblock_cur_data_scratch_id( + struct sfs_flash_fs_ctx_t *fs_ctx, + uint32_t lblock); + +/** + * \brief Gets file metadata entry index. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] fid ID of the file + * \param[out] idx Index of the file metadata in the file system + * + * \return Returns error code as specified in \ref psa_status_t + */ +psa_status_t sfs_flash_fs_mblock_get_file_idx(struct sfs_flash_fs_ctx_t *fs_ctx, + const uint8_t *fid, + uint32_t *idx); + +/** + * \brief Finalizes an update operation. + * Last step when a create/write/delete is performed. + * + * \param[in,out] fs_ctx Filesystem context + * + * \return Returns offset value in metadata block + */ +int32_t sfs_flash_fs_mblock_meta_update_finalize( + struct sfs_flash_fs_ctx_t *fs_ctx); + +/** + * \brief Writes the files data area of logical block 0 into the scratch + * block. + * + * \note The files data in the logical block 0 is stored in same physical + * block where the metadata is stored. A change in the metadata requires a + * swap of physical blocks. So, the files data stored in the current + * medadata block needs to be copied in the scratch block, unless + * the data of the file processed is located in the logical block 0. + * + * \param[in,out] fs_ctx Filesystem context + * + * \return Returns error code as specified in \ref psa_status_t + */ +psa_status_t sfs_flash_fs_mblock_migrate_lb0_data_to_scratch( + struct sfs_flash_fs_ctx_t *fs_ctx); + +/** + * \brief Reads specified file metadata. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] idx File metadata entry index + * \param[out] file_meta Pointer to file meta structure + * + * \return Returns error code as specified in \ref psa_status_t + */ +psa_status_t sfs_flash_fs_mblock_read_file_meta( + struct sfs_flash_fs_ctx_t *fs_ctx, + uint32_t idx, + struct sfs_file_meta_t *file_meta); + +/** + * \brief Reads specified logical block metadata. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] lblock Logical block number + * \param[out] block_meta Pointer to block meta structure + * + * \return Returns error code as specified in \ref psa_status_t + */ +psa_status_t sfs_flash_fs_mblock_read_block_metadata( + struct sfs_flash_fs_ctx_t *fs_ctx, + uint32_t lblock, + struct sfs_block_meta_t *block_meta); + +/** + * \brief Reserves space for a file. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] fid File ID + * \param[in] size Size of the file for which space is reserve + * \param[in] flags Flags set when the file was created + * \param[out] file_meta_idx File metadata entry index + * \param[out] file_meta File metadata entry + * \param[out] block_meta Block metadata entry + * + * \return Returns error code as specified in \ref psa_status_t + */ +psa_status_t sfs_flash_fs_mblock_reserve_file( + struct sfs_flash_fs_ctx_t *fs_ctx, + const uint8_t *fid, + size_t size, + uint32_t flags, + uint32_t *file_meta_idx, + struct sfs_file_meta_t *file_meta, + struct sfs_block_meta_t *block_meta); + +/** + * \brief Resets metablock by cleaning and initializing the metadatablock. + * + * \param[in,out] fs_ctx Filesystem context + * + * \return Returns value as specified in \ref psa_status_t + */ +psa_status_t sfs_flash_fs_mblock_reset_metablock( + struct sfs_flash_fs_ctx_t *fs_ctx); + +/** + * \brief Sets current data scratch block + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] phy_id Physical ID of scratch data block + * \param[in] lblock Logical block number + */ +void sfs_flash_fs_mblock_set_data_scratch(struct sfs_flash_fs_ctx_t *fs_ctx, + uint32_t phy_id, uint32_t lblock); + +/** + * \brief Puts logical block's metadata in scratch metadata block + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] lblock Logical block number + * \param[in] block_meta Pointer to block's metadata + * + * \return Returns error code as specified in \ref psa_status_t + */ +psa_status_t sfs_flash_fs_mblock_update_scratch_block_meta( + struct sfs_flash_fs_ctx_t *fs_ctx, + uint32_t lblock, + struct sfs_block_meta_t *block_meta); + +/** + * \brief Writes a file metadata entry into scratch metadata block. + * + * \param[in,out] fs_ctx Filesystem context + * \param[in] idx File's index in the metadata table + * \param[in] file_meta Metadata pointer + * + * \return Returns error code as specified in \ref psa_status_t + */ +psa_status_t sfs_flash_fs_mblock_update_scratch_file_meta( + struct sfs_flash_fs_ctx_t *fs_ctx, + uint32_t idx, + const struct sfs_file_meta_t *file_meta); + +#ifdef __cplusplus +} +#endif + +#endif /* __SFS_FLASH_FS_MBLOCK_H__ */ diff --git a/components/service/secure_storage/provider/secure_flash_store/secure_flash_store.c b/components/service/secure_storage/provider/secure_flash_store/secure_flash_store.c new file mode 100644 index 000000000..a9f85bd0e --- /dev/null +++ b/components/service/secure_storage/provider/secure_flash_store/secure_flash_store.c @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2019-2020, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include "flash/sfs_flash.h" +#include "flash_fs/sfs_flash_fs.h" +#include "sfs_utils.h" +#include "secure_flash_store.h" +#include <string.h> + +#define SFS_MAX_ASSET_SIZE (4096) /* TODO: comes from flash layout */ +#define SFS_CREATE_FLASH_LAYOUT /* TODO: move this to a proper place */ + +#ifndef SFS_BUF_SIZE +/* By default, set the SFS buffer size to the max asset size so that all + * requests can be handled in one iteration. + */ +#define SFS_BUF_SIZE SFS_MAX_ASSET_SIZE +#endif + +#define SFS_INVALID_UID 0 /* TODO: are there any invalid UID-s? */ + +/* Buffer to store asset data from the caller. + * Note: size must be aligned to the max flash program unit to meet the + * alignment requirement of the filesystem. + */ +static uint8_t asset_data[SFS_UTILS_ALIGN(SFS_BUF_SIZE, + SFS_FLASH_MAX_ALIGNMENT)]; + +static uint8_t g_fid[SFS_FILE_ID_SIZE]; +static struct sfs_file_info_t g_file_info; + +static sfs_flash_fs_ctx_t fs_ctx_sfs; + +/** + * \brief Maps a pair of client id and uid to a file id. + * + * \param[in] client_id Identifier of the asset's owner (client) + * \param[in] uid Identifier for the data + * \param[out] fid Identifier of the file + */ +static void sfs_get_fid(uint32_t client_id, + uint64_t uid, + uint8_t *fid) +{ + memcpy(fid, (const void *)&client_id, sizeof(client_id)); + memcpy(fid + sizeof(client_id), (const void *)&uid, sizeof(uid)); +} + +psa_status_t sfs_init(void) +{ + psa_status_t status; + + /* Initialise the SFS context */ + status = sfs_flash_fs_prepare(&fs_ctx_sfs, + sfs_flash_get_info()); +#ifdef SFS_CREATE_FLASH_LAYOUT + /* If SFS_CREATE_FLASH_LAYOUT is set, it indicates that it is required to + * create a SFS flash layout. SFS service will generate an empty and valid + * SFS flash layout to store assets. It will erase all data located in the + * assigned SFS memory area before generating the SFS layout. + * This flag is required to be set if the SFS memory area is located in + * non-persistent memory. + * This flag can be set if the SFS memory area is located in persistent + * memory without a previous valid SFS flash layout in it. That is the case + * when it is the first time in the device life that the SFS service is + * executed. + */ + if (status != PSA_SUCCESS) { + /* Remove all data in the SFS memory area and create a valid SFS flash + * layout in that area. + */ + status = sfs_flash_fs_wipe_all(&fs_ctx_sfs); + if (status != PSA_SUCCESS) { + return status; + } + + /* Attempt to initialise again */ + status = sfs_flash_fs_prepare(&fs_ctx_sfs, + sfs_flash_get_info()); + } +#endif /* SFS_CREATE_FLASH_LAYOUT */ + + + return status; +} + +psa_status_t sfs_set(uint32_t client_id, + uint64_t uid, + size_t data_length, + const void *p_data, + uint32_t create_flags) +{ + psa_status_t status; + size_t write_size; + size_t offset; + const uint8_t *data = p_data; + + data = (const uint8_t *)p_data; + + /* Check that the UID is valid */ + if (uid == SFS_INVALID_UID) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + /* Check that the create_flags does not contain any unsupported flags */ + if (create_flags & ~(TS_SECURE_STORAGE_FLAG_WRITE_ONCE | + TS_SECURE_STORAGE_FLAG_NO_CONFIDENTIALITY | + TS_SECURE_STORAGE_FLAG_NO_REPLAY_PROTECTION)) { + return PSA_ERROR_NOT_SUPPORTED; + } + + /* Set file id */ + sfs_get_fid(client_id, uid, g_fid); + + /* Read file info */ + status = sfs_flash_fs_file_get_info(&fs_ctx_sfs, g_fid, &g_file_info); + if (status == PSA_SUCCESS) { + /* If the object exists and has the write once flag set, then it + * cannot be modified. Otherwise it needs to be removed. + */ + if (g_file_info.flags & TS_SECURE_STORAGE_FLAG_WRITE_ONCE) { + return PSA_ERROR_NOT_PERMITTED; + } else { + status = sfs_flash_fs_file_delete(&fs_ctx_sfs, g_fid); + if (status != PSA_SUCCESS) { + return status; + } + } + } else if (status != PSA_ERROR_DOES_NOT_EXIST) { + /* If the file does not exist, then do nothing. + * If other error occurred, return it + */ + return status; + } + + /* Write as much of the data as will fit in the asset_data buffer */ + write_size = SFS_UTILS_MIN(data_length, sizeof(asset_data)); + + /* Read asset data from the caller */ + memcpy(asset_data, data, write_size); + data += write_size; + + /* Create the file in the file system */ + status = sfs_flash_fs_file_create(&fs_ctx_sfs, g_fid, data_length, + write_size, (uint32_t)create_flags, + asset_data); + if (status != PSA_SUCCESS) { + return status; + } + + offset = write_size; + data_length -= write_size; + + /* Iteratively read data from the caller and write it to the filesystem, in + * chunks no larger than the size of the asset_data buffer. + */ + while (data_length > 0) { + write_size = SFS_UTILS_MIN(data_length, sizeof(asset_data)); + + /* Read asset data from the caller */ + memcpy(asset_data, data, write_size); + data += write_size; + + /* Write to the file in the file system */ + status = sfs_flash_fs_file_write(&fs_ctx_sfs, g_fid, + write_size, offset, asset_data); + if (status != PSA_SUCCESS) { + /* Delete the file to avoid leaving partial data */ + (void)sfs_flash_fs_file_delete(&fs_ctx_sfs, g_fid); + return status; + } + + offset += write_size; + data_length -= write_size; + } + + return PSA_SUCCESS; +} + +psa_status_t sfs_get(uint32_t client_id, + uint64_t uid, + size_t data_offset, + size_t data_size, + void *p_data, + size_t *p_data_length) +{ + psa_status_t status; + size_t read_size; + uint8_t *data = p_data; + + data = (uint8_t *)p_data; + + /* Check that the UID is valid */ + if (uid == SFS_INVALID_UID) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + /* Set file id */ + sfs_get_fid(client_id, uid, g_fid); + + /* Read file info */ + status = sfs_flash_fs_file_get_info(&fs_ctx_sfs, g_fid, &g_file_info); + if (status != PSA_SUCCESS) { + return status; + } + + /* Boundary check the incoming request */ + if (data_offset > g_file_info.size_current) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + /* Copy the object data only from within the file boundary */ + data_size = SFS_UTILS_MIN(data_size, + g_file_info.size_current - data_offset); + + /* Update the size of the output data */ + *p_data_length = data_size; + + /* Iteratively read data from the filesystem and write it to the caller, in + * chunks no larger than the size of the asset_data buffer. + */ + do { + /* Read as much of the data as will fit in the asset_data buffer */ + read_size = SFS_UTILS_MIN(data_size, sizeof(asset_data)); + + /* Read file data from the filesystem */ + status = sfs_flash_fs_file_read(&fs_ctx_sfs, g_fid, read_size, + data_offset, asset_data); + if (status != PSA_SUCCESS) { + *p_data_length = 0; + return status; + } + + /* Write asset data to the caller */ + memcpy(data, asset_data, read_size); + data += read_size; + + data_offset += read_size; + data_size -= read_size; + } while (data_size > 0); + + return PSA_SUCCESS; +} + +psa_status_t sfs_get_info(uint32_t client_id, uint64_t uid, + struct secure_storage_response_get_info *p_info) +{ + psa_status_t status; + + /* Check that the UID is valid */ + if (uid == SFS_INVALID_UID) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + /* Set file id */ + sfs_get_fid(client_id, uid, g_fid); + + /* Read file info */ + status = sfs_flash_fs_file_get_info(&fs_ctx_sfs, g_fid, &g_file_info); + if (status != PSA_SUCCESS) { + return status; + } + + /* Copy file info to the PSA info struct */ + p_info->capacity = g_file_info.size_current; + p_info->size = g_file_info.size_current; + p_info->flags = g_file_info.flags; + + return PSA_SUCCESS; +} + +psa_status_t sfs_remove(uint32_t client_id, uint64_t uid) +{ + psa_status_t status; + + /* Check that the UID is valid */ + if (uid == SFS_INVALID_UID) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + /* Set file id */ + sfs_get_fid(client_id, uid, g_fid); + + status = sfs_flash_fs_file_get_info(&fs_ctx_sfs, g_fid, &g_file_info); + if (status != PSA_SUCCESS) { + return status; + } + + /* If the object exists and has the write once flag set, then it + * cannot be deleted. + */ + if (g_file_info.flags & TS_SECURE_STORAGE_FLAG_WRITE_ONCE) { + return PSA_ERROR_NOT_PERMITTED; + } + + /* Delete old file from the persistent area */ + return sfs_flash_fs_file_delete(&fs_ctx_sfs, g_fid); +} diff --git a/components/service/secure_storage/provider/secure_flash_store/secure_flash_store.h b/components/service/secure_storage/provider/secure_flash_store/secure_flash_store.h new file mode 100644 index 000000000..41b7aa865 --- /dev/null +++ b/components/service/secure_storage/provider/secure_flash_store/secure_flash_store.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2019-2020, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __SECURE_FLASH_STORE_H__ +#define __SECURE_FLASH_STORE_H__ + +#include <stddef.h> +#include <stdint.h> + +#include <protocols/service/psa/packed-c/status.h> +#include <protocols/service/secure_storage/packed-c/secure_storage_proto.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initializes the internal trusted storage system. + * + * \return A status indicating the success/failure of the operation + * + * \retval PSA_SUCCESS The operation completed successfully + * \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the storage + * system initialization has failed (fatal + * error) + * \retval PSA_ERROR_GENERIC_ERROR The operation failed because of an + * unspecified internal failure + */ +psa_status_t sfs_init(void); + +/** + * \brief Create a new, or modify an existing, uid/value pair + * + * Stores data in the internal storage. + * + * \param[in] client_id Identifier of the asset's owner (client) + * \param[in] uid The identifier for the data + * \param[in] data_length The size in bytes of the data in `p_data` + * \param[in] create_flags The flags that the data will be stored with + * + * \return A status indicating the success/failure of the operation + * + * \retval PSA_SUCCESS The operation completed successfully + * \retval PSA_ERROR_NOT_PERMITTED The operation failed because the + * provided `uid` value was already + * created with + * TS_SECURE_STORAGE_FLAG_WRITE_ONCE + * \retval PSA_ERROR_NOT_SUPPORTED The operation failed because one or + * more of the flags provided in + * `create_flags` is not supported or is + * not valid + * \retval PSA_ERROR_INSUFFICIENT_STORAGE The operation failed because there + * was insufficient space on the + * storage medium + * \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the + * physical storage has failed (Fatal + * error) + * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because one + * of the provided pointers (`p_data`) + * is invalid, for example is `NULL` or + * references memory the caller cannot + * access + */ +psa_status_t sfs_set(uint32_t client_id, + uint64_t uid, + size_t data_length, + const void *p_data, + uint32_t create_flags); + +/** + * \brief Retrieve data associated with a provided UID + * + * Retrieves up to `data_size` bytes of the data associated with `uid`, starting + * at `data_offset` bytes from the beginning of the data. Upon successful + * completion, the data will be placed in the `p_data` buffer, which must be at + * least `data_size` bytes in size. The length of the data returned will be in + * `p_data_length`. If `data_size` is 0, the contents of `p_data_length` will + * be set to zero. + * + * \param[in] client_id Identifier of the asset's owner (client) + * \param[in] uid The uid value + * \param[in] data_offset The starting offset of the data requested + * \param[in] data_size The amount of data requested + * \param[out] p_data_length On success, this will contain size of the data + * placed in `p_data`. + * + * \return A status indicating the success/failure of the operation + * + * \retval PSA_SUCCESS The operation completed successfully + * \retval PSA_ERROR_DOES_NOT_EXIST The operation failed because the + * provided `uid` value was not found in + * the storage + * \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the + * physical storage has failed (Fatal + * error) + * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the + * provided arguments (`p_data`, + * `p_data_length`) is invalid, for example + * is `NULL` or references memory the + * caller cannot access. In addition, this + * can also happen if `data_offset` is + * larger than the size of the data + * associated with `uid`. + */ +psa_status_t sfs_get(uint32_t client_id, + uint64_t uid, + size_t data_offset, + size_t data_size, + void *p_data, + size_t *p_data_length); + +/** + * \brief Retrieve the metadata about the provided uid + * + * Retrieves the metadata stored for a given `uid` as a `secure_storage_response_get_info` + * structure. + * + * \param[in] client_id Identifier of the asset's owner (client) + * \param[in] uid The `uid` value + * \param[out] p_info A pointer to the `secure_storage_response_get_info` struct that will + * be populated with the metadata + * + * \return A status indicating the success/failure of the operation + * + * \retval PSA_SUCCESS The operation completed successfully + * \retval PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided + * uid value was not found in the storage + * \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical + * storage has failed (Fatal error) + * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because one of the + * provided pointers(`p_info`) + * is invalid, for example is `NULL` or + * references memory the caller cannot + * access + */ +psa_status_t sfs_get_info(uint32_t client_id, uint64_t uid, + struct secure_storage_response_get_info *p_info); + +/** + * \brief Remove the provided uid and sfs associated data from the storage + * + * Deletes the data from internal storage. + * + * \param[in] client_id Identifier of the asset's owner (client) + * \param[in] uid The `uid` value + * + * \return A status indicating the success/failure of the operation + * + * \retval PSA_SUCCESS The operation completed successfully + * \retval PSA_ERROR_INVALID_ARGUMENT The operation failed because one or more + * of the given arguments were invalid (null + * pointer, wrong flags and so on) + * \retval PSA_ERROR_DOES_NOT_EXIST The operation failed because the provided + * uid value was not found in the storage + * \retval PSA_ERROR_NOT_PERMITTED The operation failed because the provided + * uid value was created with + * TS_SECURE_STORAGE_FLAG_WRITE_ONCE + * \retval PSA_ERROR_STORAGE_FAILURE The operation failed because the physical + * storage has failed (Fatal error) + */ +psa_status_t sfs_remove(uint32_t client_id, uint64_t uid); + +#ifdef __cplusplus +} +#endif + +#endif /* __SECURE_FLASH_STORE_H__ */ diff --git a/components/service/secure_storage/provider/secure_flash_store/sfs_provider.c b/components/service/secure_storage/provider/secure_flash_store/sfs_provider.c new file mode 100644 index 000000000..5c801ed67 --- /dev/null +++ b/components/service/secure_storage/provider/secure_flash_store/sfs_provider.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "sfs_provider.h" +#include "secure_flash_store.h" +#include <protocols/service/secure_storage/packed-c/secure_storage_proto.h> +#include <protocols/service/psa/packed-c/status.h> +#include <protocols/rpc/common/packed-c/status.h> +#include <components/rpc/common/endpoint/call_ep.h> + +#include <stdio.h> + +/* Handler mapping table for service */ +static const struct service_handler handler_table[] = { + {TS_SECURE_STORAGE_OPCODE_SET, sfs_set_handler}, + {TS_SECURE_STORAGE_OPCODE_GET, sfs_get_handler}, + {TS_SECURE_STORAGE_OPCODE_GET_INFO, sfs_get_info_handler}, + {TS_SECURE_STORAGE_OPCODE_REMOVE, sfs_remove_handler} +}; + +struct call_ep *sfs_provider_init(struct sfs_provider *context) +{ + struct call_ep *call_ep = NULL; + + if (context == NULL) + goto out; + + if (sfs_init() != PSA_SUCCESS) + goto out; + + service_provider_init(&context->base_provider, context, handler_table, + sizeof(handler_table) / sizeof(handler_table[0])); + + call_ep = service_provider_get_call_ep(&context->base_provider); + +out: + return call_ep; +} + +rpc_status_t sfs_set_handler(void *context, struct call_req *req) +{ + struct secure_storage_request_set *request_desc; + psa_status_t psa_status; + + /* Checking if the descriptor fits into the request buffer */ + if (req->req_buf.data_len < sizeof(struct secure_storage_request_set)) + return TS_RPC_ERROR_INVALID_REQ_BODY; + + request_desc = (struct secure_storage_request_set *)(req->req_buf.data); + + /* Checking for overflow */ + if (sizeof(struct secure_storage_request_set) + request_desc->data_length < request_desc->data_length) + return TS_RPC_ERROR_INVALID_REQ_BODY; + + /* Checking if descriptor and data fits into the request buffer */ + if (req->req_buf.data_len < sizeof(struct secure_storage_request_set) + request_desc->data_length) + return TS_RPC_ERROR_INVALID_REQ_BODY; + + psa_status = sfs_set(req->caller_id, request_desc->uid, + request_desc->data_length, + request_desc->p_data, + request_desc->create_flags); + call_req_set_opstatus(req, psa_status); + + return TS_RPC_CALL_ACCEPTED; +} + +rpc_status_t sfs_get_handler(void *context, struct call_req *req) +{ + struct secure_storage_request_get *request_desc; + psa_status_t psa_status; + + /* Checking if the descriptor fits into the request buffer */ + if (req->req_buf.data_len < sizeof(struct secure_storage_request_get)) + return TS_RPC_ERROR_INVALID_REQ_BODY; + + request_desc = (struct secure_storage_request_get *)(req->req_buf.data); + + /* Check if the requested data would fit into the response buffer. */ + if (req->resp_buf.size < request_desc->data_size) + return TS_RPC_ERROR_INVALID_RESP_BODY; + + psa_status = sfs_get(req->caller_id, request_desc->uid, + request_desc->data_offset, + request_desc->data_size, + req->resp_buf.data, &req->resp_buf.data_len); + call_req_set_opstatus(req, psa_status); + + return TS_RPC_CALL_ACCEPTED; +} + +rpc_status_t sfs_get_info_handler(void *context, struct call_req *req) +{ + struct secure_storage_request_get_info *request_desc; + struct secure_storage_response_get_info *response_desc; + struct secure_storage_response_get_info storage_info; //TODO: unnecessary? + psa_status_t psa_status; + + /* Checking if the descriptor fits into the request buffer */ + if (req->req_buf.data_len < sizeof(struct secure_storage_request_get_info)) + return TS_RPC_ERROR_INVALID_REQ_BODY; + + request_desc = (struct secure_storage_request_get_info *)(req->req_buf.data); + + /* Checking if the response structure would fit the response buffer */ + if (req->resp_buf.size < sizeof(struct secure_storage_response_get_info)) + return TS_RPC_ERROR_INVALID_RESP_BODY; + + response_desc = (struct secure_storage_response_get_info *)(req->resp_buf.data); + + psa_status = sfs_get_info(req->caller_id, request_desc->uid, &storage_info); + call_req_set_opstatus(req, psa_status); + + if (psa_status != PSA_SUCCESS) { + req->resp_buf.data_len = 0; + } + else { + response_desc->capacity = storage_info.capacity; + response_desc->size = storage_info.size; + response_desc->flags = storage_info.flags; + + req->resp_buf.data_len = sizeof(struct secure_storage_response_get_info); + } + + return TS_RPC_CALL_ACCEPTED; +} + +rpc_status_t sfs_remove_handler(void *context, struct call_req *req) +{ + struct secure_storage_request_remove *request_desc; + psa_status_t psa_status; + + /* Checking if the descriptor fits into the request buffer */ + if (req->req_buf.data_len < sizeof(struct secure_storage_request_remove)) + return TS_RPC_ERROR_INVALID_REQ_BODY; + + request_desc = (struct secure_storage_request_remove *)(req->req_buf.data); + + psa_status = sfs_remove(req->caller_id, request_desc->uid); + call_req_set_opstatus(req, psa_status); + + return TS_RPC_CALL_ACCEPTED; +} diff --git a/components/service/secure_storage/provider/secure_flash_store/sfs_provider.h b/components/service/secure_storage/provider/secure_flash_store/sfs_provider.h new file mode 100644 index 000000000..82887de8a --- /dev/null +++ b/components/service/secure_storage/provider/secure_flash_store/sfs_provider.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SFS_HANDLERS_H +#define SFS_HANDLERS_H + +#include <components/service/common/provider/service_provider.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct sfs_provider { + struct service_provider base_provider; +}; + +struct call_ep *sfs_provider_init(struct sfs_provider *context); +rpc_status_t sfs_set_handler(void *context, struct call_req *req); +rpc_status_t sfs_get_handler(void *context, struct call_req *req); +rpc_status_t sfs_get_info_handler(void *context, struct call_req *req); +rpc_status_t sfs_remove_handler(void *context, struct call_req *req); + +#ifdef __cplusplus +} +#endif + +#endif /* SFS_HANDLERS_H */ diff --git a/components/service/secure_storage/provider/secure_flash_store/sfs_utils.c b/components/service/secure_storage/provider/secure_flash_store/sfs_utils.c new file mode 100644 index 000000000..3d1627260 --- /dev/null +++ b/components/service/secure_storage/provider/secure_flash_store/sfs_utils.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017-2019, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include "sfs_utils.h" + +psa_status_t sfs_utils_check_contained_in(size_t superset_size, + size_t subset_offset, + size_t subset_size) +{ + /* Check that subset_offset is valid */ + if (subset_offset > superset_size) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + /* Check that subset_offset + subset_size fits in superset_size. + * The previous check passed, so we know that subset_offset <= superset_size + * and so the right hand side of the inequality cannot underflow. + */ + if (subset_size > (superset_size - subset_offset)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + return PSA_SUCCESS; +} + +psa_status_t sfs_utils_validate_fid(const uint8_t *fid) +{ + uint32_t fid_size = SFS_FILE_ID_SIZE; + + /* A file ID is valid if it is non-zero */ + while (fid_size--) { + if (*fid++) { + return PSA_SUCCESS; + } + } + + return PSA_ERROR_DOES_NOT_EXIST; +} diff --git a/components/service/secure_storage/provider/secure_flash_store/sfs_utils.h b/components/service/secure_storage/provider/secure_flash_store/sfs_utils.h new file mode 100644 index 000000000..4a06d4b33 --- /dev/null +++ b/components/service/secure_storage/provider/secure_flash_store/sfs_utils.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017-2020, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __SFS_UTILS_H__ +#define __SFS_UTILS_H__ + +#include <stddef.h> +#include <stdint.h> + +#include <protocols/service/psa/packed-c/status.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define SFS_FILE_ID_SIZE 12 +#define SFS_DEFAULT_EMPTY_BUFF_VAL 0 + +/** + * \brief Macro to check, at compilation time, if data fits in data buffer + * + * \param[in] err_msg Error message which will be displayed in first + * instance if the error is triggered + * \param[in] data_size Data size to check if it fits + * \param[in] data_buf_size Size of the data buffer + * + * \return Triggers a compilation error if data_size is bigger than + * data_buf_size. The compilation error should be + * "... error: 'err_msg' declared as an array with a negative size" + */ +#define SFS_UTILS_BOUND_CHECK(err_msg, data_size, data_buf_size) \ +typedef char err_msg[(data_size <= data_buf_size)*2 - 1] + +/** + * \brief Evaluates to the minimum of the two parameters. + */ +#define SFS_UTILS_MIN(x, y) (((x) < (y)) ? (x) : (y)) + +/** + * \brief Evaluates to the maximum of the two parameters. + */ +#define SFS_UTILS_MAX(x, y) (((x) > (y)) ? (x) : (y)) + +/** + * \brief Aligns a value up to the provided alignment. + * + * \param[in] x Value to be aligned + * \param[in] a Alignment (must be a power of two) + * + * \return The least value not less than \p x that is aligned to \p a. + */ +#define SFS_UTILS_ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1)) + +/** + * \brief Checks that a value is aligned to the provided alignment. + * + * \param[in] x Value to check for alignment + * \param[in] a Alignment (must be a power of two) + * + * \return 1 if \p x is aligned to \p a, 0 otherwise. + */ +#define SFS_UTILS_IS_ALIGNED(x, a) (((x) & ((a) - 1)) == 0) + +/** + * \brief Checks if a subset region is fully contained within a superset region. + * + * \param[in] superset_size Size of superset region + * \param[in] subset_offset Offset of start of subset region from start of + * superset region + * \param[in] subset_size Size of subset region + * + * \return Returns error code as specified in \ref psa_status_t + * + * \retval PSA_SUCCESS The subset is contained within the + * superset + * \retval PSA_ERROR_INVALID_ARGUMENT Otherwise + */ +psa_status_t sfs_utils_check_contained_in(size_t superset_size, + size_t subset_offset, + size_t subset_size); + +/** + * \brief Validates file ID + * + * \param[in] fid File ID + * + * \return Returns error code as specified in \ref psa_status_t + */ +psa_status_t sfs_utils_validate_fid(const uint8_t *fid); + +#ifdef __cplusplus +} +#endif + +#endif /* __SFS_UTILS_H__ */ |