diff --git a/UNITTESTS/CMakeLists.txt b/UNITTESTS/CMakeLists.txt index 1ef06cff65..52f46f5f9d 100644 --- a/UNITTESTS/CMakeLists.txt +++ b/UNITTESTS/CMakeLists.txt @@ -145,6 +145,7 @@ set(unittest-includes-base "${PROJECT_SOURCE_DIR}/../features/mbedtls" "${PROJECT_SOURCE_DIR}/../features/mbedtls/inc" "${PROJECT_SOURCE_DIR}/../features/mbedtls/mbed-crypto/inc" + "${PROJECT_SOURCE_DIR}/../features/storage/kvstore/conf" ) # Create a list for test suites. diff --git a/features/storage/TESTS/kvstore/direct_access_devicekey_test/main.cpp b/features/storage/TESTS/kvstore/direct_access_devicekey_test/main.cpp index 8a695eb590..869e335f0b 100644 --- a/features/storage/TESTS/kvstore/direct_access_devicekey_test/main.cpp +++ b/features/storage/TESTS/kvstore/direct_access_devicekey_test/main.cpp @@ -58,7 +58,6 @@ int get_virtual_TDBStore_position(uint32_t conf_start_address, uint32_t conf_si uint32_t flash_start_address; uint32_t aligned_start_address; FlashIAP flash; - static const int STORE_SECTORS = 2; int ret = flash.init(); if (ret != 0) { @@ -93,19 +92,11 @@ int get_virtual_TDBStore_position(uint32_t conf_start_address, uint32_t conf_si } } } else { - // Assumption is that last two sectors are reserved for the TDBStore - aligned_start_address = flash.get_flash_start() + flash.get_flash_size(); - - for (int i = STORE_SECTORS; i; i--) { - bd_size_t sector_size = flash.get_sector_size(aligned_start_address - 1); - aligned_start_address -= sector_size; - } - - if (aligned_start_address < flash_first_writable_sector_address) { - flash.deinit(); - return -2; - } - bd_final_size = (flash_end_address - aligned_start_address); + bd_addr_t default_start; + bd_size_t default_size; + kv_get_default_flash_addresses(&default_start, &default_size); + aligned_start_address = (uint32_t)default_start; + bd_final_size = (uint32_t)default_size; } (*tdb_start_address) = aligned_start_address; diff --git a/features/storage/kvstore/conf/filesystem/mbed_lib.json b/features/storage/kvstore/conf/filesystem/mbed_lib.json index 85b27cbf4d..836da52074 100644 --- a/features/storage/kvstore/conf/filesystem/mbed_lib.json +++ b/features/storage/kvstore/conf/filesystem/mbed_lib.json @@ -2,11 +2,11 @@ "name": "storage_filesystem", "config": { "rbp_internal_size": { - "help": "Default is the size of the 2 last sectors of internal flash", + "help": "Default is the larger of the last 2 sectors or last 14 pages of flash.", "value": "0" }, "internal_base_address": { - "help": "If default, base address is the first sector after the application code", + "help": "If default, base address is set to internal_size bytes before the end of flash.", "value": "0" }, "filesystem": { @@ -36,7 +36,7 @@ }, "target_overrides": { "MCU_PSOC6": { - "rbp_internal_size": 7168 + "rbp_internal_size": "7168" } } } diff --git a/features/storage/kvstore/conf/kv_config.cpp b/features/storage/kvstore/conf/kv_config.cpp index 5283287a10..4102c0a67b 100644 --- a/features/storage/kvstore/conf/kv_config.cpp +++ b/features/storage/kvstore/conf/kv_config.cpp @@ -150,6 +150,12 @@ static const char *filesystemstore_folder_path = NULL; using namespace mbed; +// Use the last 2 sectors or 14 pages of flash for the TDBStore by default (whichever is larger) +// For each area: must be a minimum of 1 page of reserved and 2 pages for master record +/** Minimum number of internal flash sectors required for TDBStore */ +static const int STORE_SECTORS = 2; +/** Minimum number of internal flash pages required for TDBStore */ +static const int STORE_PAGES = 14; static SingletonPtr mutex; static bool is_kv_config_initialize = false; @@ -180,14 +186,14 @@ int _calculate_blocksize_match_tdbstore(BlockDevice *bd) { bd_size_t size = bd->size(); bd_size_t erase_size = bd->get_erase_size(); + bd_size_t page_size = bd->get_program_size(); bd_size_t number_of_sector = size / erase_size; - - if (number_of_sector < 2) { - tr_warning("KV Config: There are less than two sectors - TDBStore will not work."); + bd_size_t number_of_page = size / page_size; + if (number_of_sector < STORE_SECTORS) { + tr_error("KV Config: There are less than %d sectors - TDBStore will not work.", STORE_SECTORS); return -1; } - if (number_of_sector % 2 != 0) { tr_warning("KV Config: Number of sectors is not an even number. Consider changing the BlockDevice size"); } @@ -270,175 +276,17 @@ FileSystem *_get_filesystem_default(const char *mount) #endif } -//Calculates the start address of FLASHIAP block device for TDB_INTERNAL profile. -//Last two sectors to have a predictable location for the TDBStore -int _get_flashiap_bd_default_addresses_tdb_internal(bd_addr_t *start_address, bd_size_t *size) -{ - int ret = MBED_SUCCESS; - -#if COMPONENT_FLASHIAP - - FlashIAP flash; - static const int STORE_SECTORS = 2; - - if (*start_address || *size) { - return MBED_ERROR_INVALID_ARGUMENT; - } - - if (flash.init() != 0) { - return MBED_ERROR_FAILED_OPERATION; - } - - // Lets work from end of the flash backwards - bd_addr_t curr_addr = flash.get_flash_start() + flash.get_flash_size(); - - for (int i = STORE_SECTORS; i; i--) { - bd_size_t sector_size = flash.get_sector_size(curr_addr - 1); - curr_addr -= sector_size; - } - - // Store- and application-sectors mustn't overlap - uint32_t first_wrtbl_sector_addr = - (uint32_t)(align_up(FLASHIAP_APP_ROM_END_ADDR, flash.get_sector_size(FLASHIAP_APP_ROM_END_ADDR))); - - MBED_ASSERT(curr_addr >= first_wrtbl_sector_addr); - if (curr_addr < first_wrtbl_sector_addr) { - ret = MBED_ERROR_MEDIA_FULL; - } else { - *start_address = curr_addr; - } - - flash.deinit(); - -#endif - - return ret; -} - -//Calculates address and size for FLASHIAP block device in TDB_EXTERNAL and FILESYSTEM profiles. -//The size of the block device will be 2 sectors at the ends of the internal flash for -//the use of the rbp internal TDBStore. -int _get_flashiap_bd_default_addresses_rbp(bd_addr_t *start_address, bd_size_t *size) -{ -#if COMPONENT_FLASHIAP - - bd_addr_t flash_end_address; - bd_addr_t flash_start_address; - bd_addr_t aligned_start_address; - bd_addr_t flash_first_writable_sector_address; - FlashIAP flash; - - if (*start_address != 0 || *size != 0) { - return MBED_ERROR_INVALID_ARGUMENT; - } - - int ret = flash.init(); - if (ret != 0) { - return MBED_ERROR_INITIALIZATION_FAILED; - } - - flash_first_writable_sector_address = align_up(FLASHIAP_APP_ROM_END_ADDR, flash.get_sector_size(FLASHIAP_APP_ROM_END_ADDR)); - flash_start_address = flash.get_flash_start(); - flash_end_address = flash_start_address + flash.get_flash_size();; - *start_address = flash_end_address - 1; - aligned_start_address = align_down(*start_address, flash.get_sector_size(*start_address)); - *size = (flash_end_address - aligned_start_address) * 2; - *start_address = (flash_end_address - *size); - aligned_start_address = align_down(*start_address, flash.get_sector_size(*start_address)); - - flash.deinit(); - - if (aligned_start_address < flash_first_writable_sector_address) { - tr_error("KV Config: Internal block device start address overlapped ROM address "); - return MBED_ERROR_INITIALIZATION_FAILED; - } - -#endif - - return MBED_SUCCESS; - -} - BlockDevice *_get_blockdevice_FLASHIAP(bd_addr_t start_address, bd_size_t size) { #if COMPONENT_FLASHIAP - - bd_addr_t flash_end_address; - bd_addr_t flash_start_address; - bd_addr_t flash_first_writable_sector_address; - bd_addr_t aligned_start_address; - bd_addr_t aligned_end_address; - bd_addr_t end_address; - FlashIAP flash; - - int ret = flash.init(); + int ret = kv_get_flash_bounds_from_config(&start_address, &size); if (ret != 0) { + tr_error("KV Config: Determination of internal block device bounds failed. The configured start address/size is likely invalid."); return NULL; } - //Get flash parameters before starting - flash_first_writable_sector_address = align_up(FLASHIAP_APP_ROM_END_ADDR, flash.get_sector_size(FLASHIAP_APP_ROM_END_ADDR)); - flash_start_address = flash.get_flash_start(); - flash_end_address = flash_start_address + flash.get_flash_size();; - - //Non default configuration - if (start_address != 0) { - - aligned_start_address = align_down(start_address, flash.get_sector_size(start_address)); - if (start_address != aligned_start_address) { - tr_error("KV Config: Internal block device start address is not aligned. Better use %02llx", aligned_start_address); - flash.deinit(); - return NULL; - } - - if (size == 0) { - //The block device will have all space from start address to the end of the flash - size = (flash_end_address - start_address); - - static FlashIAPBlockDevice bd(start_address, size); - flash.deinit(); - return &bd; - } - - if (size != 0) { - end_address = start_address + size; - if (end_address > flash_end_address) { - tr_error("KV Config: Internal block device end address is out of boundaries"); - flash.deinit(); - return NULL; - } - - aligned_end_address = align_up(end_address, flash.get_sector_size(end_address - 1)); - if (end_address != aligned_end_address) { - tr_error("KV Config: Internal block device start address is not aligned. Consider changing the size parameter"); - flash.deinit(); - return NULL; - } - - static FlashIAPBlockDevice bd(start_address, size); - flash.deinit(); - return &bd; - } - } - - //Non default configuration start_address = 0 - start_address = flash_end_address - size; - aligned_start_address = align_down(start_address, flash.get_sector_size(start_address)); - if (start_address != aligned_start_address) { - tr_error("KV Config: Internal block device start address is not aligned. Consider changing the size parameter"); - flash.deinit(); - return NULL; - } - - flash.deinit(); - - if (aligned_start_address < flash_first_writable_sector_address) { - tr_error("KV Config: Internal block device start address overlapped ROM address "); - return NULL; - } - static FlashIAPBlockDevice bd(aligned_start_address, size); + static FlashIAPBlockDevice bd(start_address, size); return &bd; - #else return NULL; #endif @@ -474,6 +322,9 @@ BlockDevice *_get_blockdevice_SPIF(bd_addr_t start_address, bd_size_t size) return NULL; } + start_address = aligned_start_address; + size = aligned_end_address - aligned_start_address; + static SlicingBlockDevice sbd(&bd, aligned_start_address, aligned_end_address); return &sbd; @@ -515,6 +366,9 @@ BlockDevice *_get_blockdevice_QSPIF(bd_addr_t start_address, bd_size_t size) return NULL; } + start_address = aligned_start_address; + size = aligned_end_address - aligned_start_address; + static SlicingBlockDevice sbd(&bd, aligned_start_address, aligned_end_address); return &sbd; @@ -552,6 +406,9 @@ BlockDevice *_get_blockdevice_DATAFLASH(bd_addr_t start_address, bd_size_t size) return NULL; } + start_address = aligned_start_address; + size = aligned_end_address - aligned_start_address; + static SlicingBlockDevice sbd(&bd, aligned_start_address, aligned_end_address); return &sbd; @@ -618,6 +475,10 @@ BlockDevice *_get_blockdevice_SD(bd_addr_t start_address, bd_size_t size) } aligned_end_address = align_down(aligned_end_address, bd.get_erase_size(aligned_end_address)); + + start_address = aligned_start_address; + size = aligned_end_address - aligned_start_address; + static SlicingBlockDevice sbd(&bd, aligned_start_address, aligned_end_address); return &sbd; @@ -691,6 +552,10 @@ BlockDevice *_get_blockdevice_other(bd_addr_t start_address, bd_size_t size) } aligned_end_address = align_down(aligned_end_address, bd->get_erase_size(aligned_end_address)); + + start_address = aligned_start_address; + size = aligned_end_address - aligned_start_address; + static SlicingBlockDevice sbd(bd, aligned_start_address, aligned_end_address); return &sbd; } @@ -700,57 +565,71 @@ MBED_WEAK BlockDevice *get_other_blockdevice() return NULL; } -int _storage_config_TDB_INTERNAL() +int _create_internal_tdb(BlockDevice **internal_bd, KVStore **internal_tdb, bd_size_t size, bd_addr_t start_address) { -#if COMPONENT_FLASHIAP - bd_size_t internal_size = MBED_CONF_STORAGE_TDB_INTERNAL_INTERNAL_SIZE; - bd_addr_t internal_start_address = MBED_CONF_STORAGE_TDB_INTERNAL_INTERNAL_BASE_ADDRESS; int ret; - if (internal_size == 0 && internal_start_address == 0) { + //Get the default address and size for the TDBStore + if (size == 0 && start_address == 0) { //Calculate the block device size and start address in case default values are used. - ret = _get_flashiap_bd_default_addresses_tdb_internal(&internal_start_address, &internal_size); + ret = kv_get_default_flash_addresses(&start_address, &size); if (ret != MBED_SUCCESS) { - return ret; + return MBED_ERROR_FAILED_OPERATION; } } - //Get internal memory FLASHIAP block device. - kvstore_config.internal_bd = GET_BLOCKDEVICE(INTERNAL_BLOCKDEVICE_NAME, internal_start_address, internal_size); - if (kvstore_config.internal_bd == NULL) { + //Create internal FLASHIAP block device + *internal_bd = GET_BLOCKDEVICE(INTERNAL_BLOCKDEVICE_NAME, start_address, size); + if (*internal_bd == NULL) { tr_error("KV Config: Fail to get internal BlockDevice."); - return MBED_ERROR_FAILED_OPERATION; + return MBED_ERROR_FAILED_OPERATION ; } - - ret = kvstore_config.internal_bd->init(); + // Initialize internal block device + ret = (*internal_bd)->init(); if (ret != MBED_SUCCESS) { tr_error("KV Config: Fail to init internal BlockDevice."); - return MBED_ERROR_FAILED_OPERATION; + return MBED_ERROR_FAILED_OPERATION ; } - //Check that internal flash has 2 or more sectors - if (_calculate_blocksize_match_tdbstore(kvstore_config.internal_bd) != MBED_SUCCESS) { - tr_error("KV Config: Can not create TDBStore with less then 2 sector."); + //Check if TDBStore has at least 2 sectors or 14 pages. + if (_calculate_blocksize_match_tdbstore(*internal_bd) != MBED_SUCCESS) { + tr_error("KV Config: Can not create TDBStore with less then %d sectors.", STORE_SECTORS); return MBED_ERROR_INVALID_ARGUMENT; } - //Deinitialize internal block device and TDB will reinitialize and take control on it. - ret = kvstore_config.internal_bd->deinit(); + //Deinitialize internal block device and TDB will reinitialize and take control of it. + ret = (*internal_bd)->deinit(); if (ret != MBED_SUCCESS) { tr_error("KV Config: Fail to deinit internal BlockDevice."); return MBED_ERROR_FAILED_OPERATION; } - //Create a TDBStore in the internal FLASHIAP block device. - static TDBStore tdb_internal(kvstore_config.internal_bd); - kvstore_config.internal_store = &tdb_internal; + //Create internal TDBStore + static TDBStore tdb_internal(*internal_bd); + *internal_tdb = &tdb_internal; - ret = kvstore_config.internal_store->init(); + ret = (*internal_tdb)->init(); if (ret != MBED_SUCCESS) { tr_error("KV Config: Fail to init internal TDBStore."); return ret; } + + return MBED_SUCCESS; +} + +int _storage_config_TDB_INTERNAL() +{ +#if COMPONENT_FLASHIAP + bd_size_t internal_size = MBED_CONF_STORAGE_TDB_INTERNAL_INTERNAL_SIZE; + bd_addr_t internal_start_address = MBED_CONF_STORAGE_TDB_INTERNAL_INTERNAL_BASE_ADDRESS; + + int ret = _create_internal_tdb(&kvstore_config.internal_bd, &kvstore_config.internal_store, internal_size, internal_start_address); + if (MBED_SUCCESS != ret) { + tr_error("KV Config: Fail to create internal TDBStore"); + return ret; + } + kvstore_config.kvstore_main_instance = kvstore_config.internal_store; @@ -790,40 +669,9 @@ int _storage_config_TDB_EXTERNAL() bd_size_t internal_rbp_size = MBED_CONF_STORAGE_TDB_EXTERNAL_RBP_INTERNAL_SIZE; bd_addr_t internal_start_address = MBED_CONF_STORAGE_TDB_EXTERNAL_INTERNAL_BASE_ADDRESS; - //Get the default address and size for internal rbp TDBStore - if (internal_rbp_size == 0 && internal_start_address == 0) { - //Calculate the block device size and start address in case default values are used. - if (_get_flashiap_bd_default_addresses_rbp(&internal_start_address, &internal_rbp_size) != MBED_SUCCESS) { - return MBED_ERROR_FAILED_OPERATION; - } - } - - //Create internal FLASHIAP block device - kvstore_config.internal_bd = GET_BLOCKDEVICE(INTERNAL_BLOCKDEVICE_NAME, internal_start_address, internal_rbp_size); - if (kvstore_config.internal_bd == NULL) { - tr_error("KV Config: Fail to get internal BlockDevice."); - return MBED_ERROR_FAILED_OPERATION ; - } - - int ret = kvstore_config.internal_bd->init(); - if (ret != MBED_SUCCESS) { - tr_error("KV Config: Fail to init internal BlockDevice."); - return MBED_ERROR_FAILED_OPERATION ; - } - - //Check if TDBStore has at least 2 sector. - if (_calculate_blocksize_match_tdbstore(kvstore_config.internal_bd) != MBED_SUCCESS) { - tr_error("KV Config: Can not create TDBStore with less then 2 sector."); - return MBED_ERROR_INVALID_ARGUMENT; - } - - //Create internal TDBStore - static TDBStore tdb_internal(kvstore_config.internal_bd); - kvstore_config.internal_store = &tdb_internal; - - ret = kvstore_config.internal_store->init(); - if (ret != MBED_SUCCESS) { - tr_error("KV Config: Fail to init internal TDBStore."); + int ret = _create_internal_tdb(&kvstore_config.internal_bd, &kvstore_config.internal_store, internal_rbp_size, internal_start_address); + if (MBED_SUCCESS != ret) { + tr_error("KV Config: Fail to create internal TDBStore"); return ret; } @@ -912,9 +760,9 @@ int _storage_config_tdb_external_common() return MBED_ERROR_FAILED_OPERATION ; } - //Check that there is at least 2 sector for the external TDBStore + //Check that there is at least 2 sectors or 14 pages for the external TDBStore if (_calculate_blocksize_match_tdbstore(kvstore_config.external_bd) != MBED_SUCCESS) { - tr_error("KV Config: Can not create TDBStore with less then 2 sector."); + tr_error("KV Config: Can not create TDBStore with less then 2 sectors or 14 pages."); return MBED_ERROR_INVALID_SIZE; } @@ -965,47 +813,9 @@ int _storage_config_FILESYSTEM() bd_size_t internal_rbp_size = MBED_CONF_STORAGE_FILESYSTEM_RBP_INTERNAL_SIZE; bd_addr_t internal_start_address = MBED_CONF_STORAGE_FILESYSTEM_INTERNAL_BASE_ADDRESS; - //Get the default address and size for internal rbp TDBStore - if (internal_rbp_size == 0 && internal_start_address == 0) { - //Calculate the block device size and start address in case default values are used. - if (_get_flashiap_bd_default_addresses_rbp(&internal_start_address, &internal_rbp_size) != MBED_SUCCESS) { - return MBED_ERROR_FAILED_OPERATION; - } - } - - //Get internal FLASHIAP block device - kvstore_config.internal_bd = GET_BLOCKDEVICE(INTERNAL_BLOCKDEVICE_NAME, internal_start_address, internal_rbp_size); - if (kvstore_config.internal_bd == NULL) { - tr_error("KV Config: Fail to get internal BlockDevice "); - return MBED_ERROR_FAILED_OPERATION ; - } - - int ret = kvstore_config.internal_bd->init(); - if (ret != MBED_SUCCESS) { - tr_error("KV Config: Fail to init internal BlockDevice "); - return MBED_ERROR_FAILED_OPERATION ; - } - - //Check that internal flash has 2 or more sectors - if (_calculate_blocksize_match_tdbstore(kvstore_config.internal_bd) != MBED_SUCCESS) { - tr_error("KV Config: Can not create TDBStore with less then 2 sector."); - return MBED_ERROR_INVALID_ARGUMENT; - } - - //Deinitialize internal block device and TDB will reinitialize and take control on it. - ret = kvstore_config.internal_bd->deinit(); - if (ret != MBED_SUCCESS) { - tr_error("KV Config: Fail to deinit internal BlockDevice."); - return MBED_ERROR_FAILED_OPERATION; - } - - //Create internal TDBStore for rbp - static TDBStore tdb_internal(kvstore_config.internal_bd); - kvstore_config.internal_store = &tdb_internal; - - ret = kvstore_config.internal_store->init(); - if (ret != MBED_SUCCESS) { - tr_error("KV Config: Fail to init internal TDBStore"); + int ret = _create_internal_tdb(&kvstore_config.internal_bd, &kvstore_config.internal_store, internal_rbp_size, internal_start_address); + if (MBED_SUCCESS != ret) { + tr_error("KV Config: Fail to create internal TDBStore"); return ret; } @@ -1181,3 +991,131 @@ exit: mutex->unlock(); return ret; } + +int kv_get_default_flash_addresses(bd_addr_t *start_address, bd_size_t *size) +{ + int ret = MBED_SUCCESS; + +#if COMPONENT_FLASHIAP + FlashIAP flash; + if (flash.init() != 0) { + return MBED_ERROR_INITIALIZATION_FAILED; + } + + // Let's work from end of the flash backwards + bd_addr_t end_of_flash = flash.get_flash_start() + flash.get_flash_size(); + bd_addr_t curr_addr = end_of_flash; + bd_size_t sector_space = 0; + + for (int i = STORE_SECTORS; i; i--) { + bd_size_t sector_size = flash.get_sector_size(curr_addr - 1); + sector_space += sector_size; + } + + bd_size_t page_space = flash.get_page_size() * STORE_PAGES; + if (sector_space > page_space) { + curr_addr -= sector_space; + *size = sector_space; + } else { + curr_addr -= page_space; + // Align to 2 sector boundary so that garbage collection works properly + curr_addr = align_down(curr_addr, 2 * flash.get_sector_size(curr_addr)); + *size = end_of_flash - curr_addr; + } + + // Store- and application-sectors mustn't overlap + uint32_t first_wrtbl_sector_addr = + (uint32_t)(align_up(FLASHIAP_APP_ROM_END_ADDR, flash.get_sector_size(FLASHIAP_APP_ROM_END_ADDR))); + + MBED_ASSERT(curr_addr >= first_wrtbl_sector_addr); + if (curr_addr < first_wrtbl_sector_addr) { + ret = MBED_ERROR_MEDIA_FULL; + } else { + *start_address = curr_addr; + } + + flash.deinit(); +#endif + + return ret; +} + +int kv_get_flash_bounds_from_config(bd_addr_t *start_address, bd_size_t *size) +{ +#if COMPONENT_FLASHIAP + + bd_addr_t flash_end_address; + bd_addr_t flash_start_address; + bd_addr_t flash_first_writable_sector_address; + bd_addr_t aligned_start_address; + bd_addr_t aligned_end_address; + bd_addr_t end_address; + FlashIAP flash; + + if (!start_address || !size) { + return MBED_ERROR_INVALID_ARGUMENT; + } + + int ret = flash.init(); + if (ret != 0) { + return MBED_ERROR_INITIALIZATION_FAILED; + } + + // Get flash parameters + flash_first_writable_sector_address = align_up(FLASHIAP_APP_ROM_END_ADDR, flash.get_sector_size(FLASHIAP_APP_ROM_END_ADDR)); + flash_start_address = flash.get_flash_start(); + flash_end_address = flash_start_address + flash.get_flash_size(); + + if (*start_address == 0) { + if (*size == 0) { + //The block device will have all space from start address to the end of the flash + *size = flash.get_flash_size(); + } + + *start_address = flash_end_address - *size; + aligned_start_address = align_down(*start_address, flash.get_sector_size(*start_address)); + if (*start_address != aligned_start_address) { + // Start address not aligned - size should likely be changed so that it is + flash.deinit(); + return MBED_ERROR_INVALID_SIZE; + } + } else { + aligned_start_address = align_down(*start_address, flash.get_sector_size(*start_address)); + if (*start_address != aligned_start_address) { + // Start address not aligned - size should likely be changed so that it is + flash.deinit(); + return MBED_ERROR_INVALID_SIZE; + } + + if (*size == 0) { + //The block device will have all space from start address to the end of the flash + *size = (flash_end_address - *start_address); + } else { + // Do checks on end address to make sure configured start address/size are good + + end_address = *start_address + *size; + if (end_address > flash_end_address) { + // End address is out of flash bounds + flash.deinit(); + return MBED_ERROR_INVALID_SIZE; + } + + aligned_end_address = align_up(end_address, flash.get_sector_size(end_address - 1)); + if (end_address != aligned_end_address) { + // End address not aligned - size should likely be changed so that it is + flash.deinit(); + return MBED_ERROR_INVALID_SIZE; + } + } + } + + flash.deinit(); + + if (*start_address < flash_first_writable_sector_address) { + // Calculated start address overlaps with ROM + return MBED_ERROR_MEDIA_FULL; + } +#endif + + return MBED_SUCCESS; +} diff --git a/features/storage/kvstore/conf/kv_config.h b/features/storage/kvstore/conf/kv_config.h index 660a6bdd88..f16688fd5e 100644 --- a/features/storage/kvstore/conf/kv_config.h +++ b/features/storage/kvstore/conf/kv_config.h @@ -16,6 +16,8 @@ #ifndef _KV_CONFIG #define _KV_CONFIG +#include "features/storage/blockdevice/BlockDevice.h" + #ifdef __cplusplus extern "C" { #endif @@ -42,6 +44,32 @@ int kv_init_storage_config(); */ const char *get_filesystemstore_folder_path(); +/** + * @brief Get the default TDBStore flash start address and size. + * + * @param[out] start_address Default TDBStore start address in flash. + * @param[out] size Default TDBStore size. + * + * @returns MBED_SUCCESS Success. + * MBED_ERROR_INITIALIZATION_FAILED Failed to initialize flash driver. + * MBED_ERROR_MEDIA_FULL Default TDBStore space overlaps with program memory. + */ +int kv_get_default_flash_addresses(mbed::bd_addr_t *start_address, mbed::bd_size_t *size); + +/** + * @brief Get the TDBStore flash bounds from the configured start address and size. + * + * @param[inout] start_address Configured TDBStore start address in flash. + * @param[inout] size Configured TDBStore size. If 0, the size will be from the start address to the end of flash + * + * @returns MBED_SUCCESS Success. + * MBED_ERROR_INVALID_ARGUMENT One of the arguments is NULL or both the configured start address and size are 0. + * MBED_ERROR_INITIALIZATION_FAILED Failed to initialize flash driver. + * MBED_ERROR_INVALID_SIZE Configured size results in misaligned start/end address or end address past the end of flash. + * MBED_ERROR_MEDIA_FULL Configured start address/size results in bounds overlapping with program memory. + */ +int kv_get_flash_bounds_from_config(mbed::bd_addr_t *start_address, mbed::bd_size_t *size); + #ifdef __cplusplus } // closing brace for extern "C" #endif diff --git a/features/storage/kvstore/conf/tdb_external/mbed_lib.json b/features/storage/kvstore/conf/tdb_external/mbed_lib.json index b4d0fb6923..af9b80ec5d 100644 --- a/features/storage/kvstore/conf/tdb_external/mbed_lib.json +++ b/features/storage/kvstore/conf/tdb_external/mbed_lib.json @@ -2,11 +2,11 @@ "name": "storage_tdb_external", "config": { "rbp_internal_size": { - "help": "Default is the size of the 2 last sectors of internal flash", + "help": "Default is the larger of the last 2 sectors or last 14 pages of flash.", "value": "0" }, "internal_base_address": { - "help": "If default, the base address is set to the first sector after the application code ends.", + "help": "If default, the base address is set to internal_size bytes before the end of flash.", "value": "0" }, "blockdevice": { diff --git a/features/storage/kvstore/conf/tdb_internal/mbed_lib.json b/features/storage/kvstore/conf/tdb_internal/mbed_lib.json index f0948de855..4289423c38 100644 --- a/features/storage/kvstore/conf/tdb_internal/mbed_lib.json +++ b/features/storage/kvstore/conf/tdb_internal/mbed_lib.json @@ -2,11 +2,11 @@ "name": "storage_tdb_internal", "config": { "internal_size": { - "help": "Size of the FlashIAP block device. default size will be from internal_base_address till the end of the internal flash.", + "help": "Size of the FlashIAP block device. Default size will be the larger of the last 2 sectors or last 14 pages of flash.", "value": "0" }, "internal_base_address": { - "help": "If default, the base address is set to the first sector after the application code ends.", + "help": "If default, the base address is set to internal_size bytes before the end of flash.", "value": "0" } }, diff --git a/features/storage/kvstore/direct_access_devicekey/DirectAccessDevicekey.cpp b/features/storage/kvstore/direct_access_devicekey/DirectAccessDevicekey.cpp index d5a0a3a476..2bd1930dfd 100644 --- a/features/storage/kvstore/direct_access_devicekey/DirectAccessDevicekey.cpp +++ b/features/storage/kvstore/direct_access_devicekey/DirectAccessDevicekey.cpp @@ -23,6 +23,7 @@ #include "mbed_error.h" #include "MbedCRC.h" #include "mbed_trace.h" +#include "kv_config.h" #define TRACE_GROUP "DADK" using namespace mbed; @@ -82,7 +83,7 @@ int direct_access_to_devicekey(uint32_t tdb_start_offset, uint32_t tdb_end_offse status = calc_area_params(&flash, tdb_start_offset, tdb_end_offset, area_params); if (status != MBED_SUCCESS) { - tr_error("Couldn't calulate Area Params - err: %d", status); + tr_error("Couldn't calculate Area Params - err: %d", status); goto exit_point; } @@ -108,21 +109,17 @@ exit_point: return status; } -int get_expected_internal_TDBStore_position(uint32_t *out_tdb_start_offset, uint32_t *out_tdb_end_offset) +int get_expected_internal_TDBStore_position(uint32_t *out_tdb_start_offset, uint32_t *out_tdb_end_offset) { - uint32_t flash_end_address; - uint32_t flash_start_address; - uint32_t aligned_start_address; - uint32_t aligned_end_address; + bd_addr_t tdb_start_address; + bd_size_t tdb_size; FlashIAP flash; - bool is_default_configuration = false; - uint32_t tdb_size; if (strcmp(STR(MBED_CONF_STORAGE_STORAGE_TYPE), "FILESYSTEM") == 0) { #ifndef MBED_CONF_STORAGE_FILESYSTEM_INTERNAL_BASE_ADDRESS return MBED_ERROR_ITEM_NOT_FOUND; #else - *out_tdb_start_offset = MBED_CONF_STORAGE_FILESYSTEM_INTERNAL_BASE_ADDRESS; + tdb_start_address = MBED_CONF_STORAGE_FILESYSTEM_INTERNAL_BASE_ADDRESS; tdb_size = MBED_CONF_STORAGE_FILESYSTEM_RBP_INTERNAL_SIZE; #endif @@ -130,7 +127,7 @@ int get_expected_internal_TDBStore_position(uint32_t *out_tdb_start_offset, uin #ifndef MBED_CONF_STORAGE_TDB_EXTERNAL_INTERNAL_BASE_ADDRESS return MBED_ERROR_ITEM_NOT_FOUND; #else - *out_tdb_start_offset = MBED_CONF_STORAGE_TDB_EXTERNAL_INTERNAL_BASE_ADDRESS; + tdb_start_address = MBED_CONF_STORAGE_TDB_EXTERNAL_INTERNAL_BASE_ADDRESS; tdb_size = MBED_CONF_STORAGE_TDB_EXTERNAL_RBP_INTERNAL_SIZE; #endif @@ -139,52 +136,28 @@ int get_expected_internal_TDBStore_position(uint32_t *out_tdb_start_offset, uin #ifndef MBED_CONF_STORAGE_TDB_INTERNAL_INTERNAL_BASE_ADDRESS return MBED_ERROR_ITEM_NOT_FOUND; #else - *out_tdb_start_offset = MBED_CONF_STORAGE_TDB_INTERNAL_INTERNAL_BASE_ADDRESS; + tdb_start_address = MBED_CONF_STORAGE_TDB_INTERNAL_INTERNAL_BASE_ADDRESS; tdb_size = MBED_CONF_STORAGE_TDB_INTERNAL_INTERNAL_SIZE; #endif } else { return MBED_ERROR_UNSUPPORTED; } - *out_tdb_end_offset = (*out_tdb_start_offset) + tdb_size; - - if ((*out_tdb_start_offset == 0) && (tdb_size == 0)) { - is_default_configuration = true; - } else if ((*out_tdb_start_offset == 0) || (tdb_size == 0)) { - return MBED_ERROR_UNSUPPORTED; + int ret; + if ((tdb_start_address == 0) && (tdb_size == 0)) { + ret = kv_get_default_flash_addresses(&tdb_start_address, &tdb_size); + if (ret != MBED_SUCCESS) { + return MBED_ERROR_FAILED_OPERATION; + } } - int ret = flash.init(); - if (ret != 0) { + ret = kv_get_flash_bounds_from_config(&tdb_start_address, &tdb_size); + if (ret != MBED_SUCCESS) { return MBED_ERROR_FAILED_OPERATION; } - uint32_t flash_first_writable_sector_address = (uint32_t)(align_up(FLASHIAP_APP_ROM_END_ADDR, - flash.get_sector_size(FLASHIAP_APP_ROM_END_ADDR))); - - //Get flash parameters before starting - flash_start_address = flash.get_flash_start(); - flash_end_address = flash_start_address + flash.get_flash_size(); - - if (!is_default_configuration) { - aligned_start_address = align_down(*out_tdb_start_offset, flash.get_sector_size(*out_tdb_start_offset)); - aligned_end_address = align_up(*out_tdb_end_offset, flash.get_sector_size(*out_tdb_end_offset - 1)); - if ((*out_tdb_start_offset != aligned_start_address) || (*out_tdb_end_offset != aligned_end_address) - || (*out_tdb_end_offset > flash_end_address)) { - flash.deinit(); - return MBED_ERROR_INVALID_OPERATION; - } - } else { - aligned_start_address = flash_end_address - (flash.get_sector_size(flash_end_address - 1) * 2); - if (aligned_start_address < flash_first_writable_sector_address) { - flash.deinit(); - return MBED_ERROR_INVALID_OPERATION; - } - *out_tdb_start_offset = aligned_start_address; - *out_tdb_end_offset = flash_end_address; - } - - flash.deinit(); + *out_tdb_start_offset = tdb_start_address; + *out_tdb_end_offset = tdb_start_address + tdb_size; return MBED_SUCCESS; } diff --git a/features/storage/kvstore/tdbstore/TDBStore.cpp b/features/storage/kvstore/tdbstore/TDBStore.cpp index 43424b1d50..fd7d8ce3c0 100644 --- a/features/storage/kvstore/tdbstore/TDBStore.cpp +++ b/features/storage/kvstore/tdbstore/TDBStore.cpp @@ -25,6 +25,7 @@ #include "mbed_assert.h" #include "mbed_wait_api.h" #include "MbedCRC.h" +#include "FlashIAP.h" using namespace mbed; @@ -110,6 +111,11 @@ static inline uint32_t align_up(uint32_t val, uint32_t size) return (((val - 1) / size) + 1) * size; } +static inline uint32_t align_down(uint64_t val, uint64_t size) +{ + return (((val) / size)) * size; +} + static uint32_t calc_crc(uint32_t init_crc, uint32_t data_size, const void *data_buf) { @@ -1422,7 +1428,6 @@ int TDBStore::reserved_data_get(void *reserved_data, size_t reserved_data_buf_si return ret; } - void TDBStore::offset_in_erase_unit(uint8_t area, uint32_t offset, uint32_t &offset_from_start, uint32_t &dist_to_end) {