From 2d69535481a03ed6b7ff6d18d835cbc4878c1fd5 Mon Sep 17 00:00:00 2001 From: Sean Kyer Date: Thu, 9 Jan 2025 16:25:05 -0800 Subject: [PATCH 1/3] subsystem: settings: Add ITS backend Add settings_its backend in order for a non-secure Bluetooth application to be able to save Bluetooth settings to persistent storage. Signed-off-by: Sean Kyer --- include/zephyr/psa/key_ids.h | 4 + subsys/settings/Kconfig | 38 +++++ subsys/settings/src/CMakeLists.txt | 1 + subsys/settings/src/settings_its.c | 248 +++++++++++++++++++++++++++++ 4 files changed, 291 insertions(+) create mode 100644 subsys/settings/src/settings_its.c diff --git a/include/zephyr/psa/key_ids.h b/include/zephyr/psa/key_ids.h index 851d1349812d..91eb98d9bb5b 100644 --- a/include/zephyr/psa/key_ids.h +++ b/include/zephyr/psa/key_ids.h @@ -44,6 +44,10 @@ typedef uint32_t psa_key_id_t; #define ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_BEGIN (psa_key_id_t)0x20010000 #define ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_SIZE 0x100 /* 256 */ +/** PSA key ID range to be used by TF-M ITS */ +#define ZEPHYR_PSA_TFM_ITS_KEY_ID_RANGE_BEGIN (psa_key_id_t)0x20010100 +#define ZEPHYR_PSA_TFM_ITS_KEY_ID_RANGE_SIZE 0x10000 /* 64 Ki */ + /** PSA key ID range to be used by the end-user application. */ #define ZEPHYR_PSA_APPLICATION_KEY_ID_RANGE_BEGIN (psa_key_id_t)0x30000000 #define ZEPHYR_PSA_APPLICATION_KEY_ID_RANGE_SIZE 0x100000 /* 1 Mi */ diff --git a/subsys/settings/Kconfig b/subsys/settings/Kconfig index fdb3c4bb3ce2..861431ecbd58 100644 --- a/subsys/settings/Kconfig +++ b/subsys/settings/Kconfig @@ -1,4 +1,5 @@ # Copyright (c) 2018 Nordic Semiconductor ASA +# Copyright (c) 2025 Analog Devices, Inc. # SPDX-License-Identifier: Apache-2.0 menuconfig SETTINGS @@ -36,6 +37,7 @@ choice SETTINGS_BACKEND default SETTINGS_NVS if NVS default SETTINGS_FCB if FCB default SETTINGS_FILE if FILE_SYSTEM + default SETTINGS_TFM_ITS if TFM_PARTITION_INTERNAL_TRUSTED_STORAGE default SETTINGS_NONE help Storage back-end to be used by the settings subsystem. @@ -109,6 +111,19 @@ config SETTINGS_CUSTOM help Use a custom settings storage back-end. +config SETTINGS_TFM_ITS + bool "Internal Trusted Storage (ITS) settings backend" + depends on TFM_PARTITION_INTERNAL_TRUSTED_STORAGE + help + Enables Internal Trusted Storage (ITS) Settings backend, which an app will be able + to use to store sensitive information. + ITS backend can be used for storing sensitive information such as keys, passwords, + or other secrets. + Note: ITS is intended to store sensitive data on-chip, such as cryptographic keys, + credentials and configuration data and is not intended for storing large amounts of data. + Note: This settings backend compacts settings data into as few ITS nodes as possible. + On every save, the entire settings array is written to ITS. + config SETTINGS_NONE bool "NONE" help @@ -219,4 +234,27 @@ config SETTINGS_SHELL size of the shell thread may need to be increased to accommodate this feature. +if SETTINGS_TFM_ITS + +config SETTINGS_TFM_ITS_NUM_ENTRIES + int "Maximum number of settings entries" + default 10 + help + Configures the maximum number of settings possible to be stored to PSA ITS. + Note: This value determines the size of a statically allocated buffer to hold + all settings entries in memory at all times. + +config SETTINGS_TFM_ITS_LAZY_PERSIST_DELAY_MS + int "Milliseconds delay before persisting settings" + default 500 + help + ITS may block for a long period of time when writing to flash, which may be + unacceptable for time-sensitive events. + Data is always persisted to ITS using k_work_delayable, instead of happening in + the same context as settings_its_save, this option sets the delay. + The delay is useful in cases where a PSA ITS write may block a time sensitive + event, Bluetooth pairing for example, that requires a sequence of settings writes. + +endif # SETTINGS_TFM_ITS + endif # SETTINGS diff --git a/subsys/settings/src/CMakeLists.txt b/subsys/settings/src/CMakeLists.txt index 4aa797fbb350..59baec51bef7 100644 --- a/subsys/settings/src/CMakeLists.txt +++ b/subsys/settings/src/CMakeLists.txt @@ -14,3 +14,4 @@ zephyr_sources_ifdef(CONFIG_SETTINGS_NVS settings_nvs.c) zephyr_sources_ifdef(CONFIG_SETTINGS_NONE settings_none.c) zephyr_sources_ifdef(CONFIG_SETTINGS_SHELL settings_shell.c) zephyr_sources_ifdef(CONFIG_SETTINGS_ZMS settings_zms.c) +zephyr_sources_ifdef(CONFIG_SETTINGS_TFM_ITS settings_its.c) diff --git a/subsys/settings/src/settings_its.c b/subsys/settings/src/settings_its.c new file mode 100644 index 000000000000..7ecf0acce620 --- /dev/null +++ b/subsys/settings/src/settings_its.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2025 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include + +LOG_MODULE_DECLARE(settings, CONFIG_SETTINGS_LOG_LEVEL); + +K_MUTEX_DEFINE(worker_mutex); +static struct k_work_delayable worker; + +struct setting_entry { + char name[SETTINGS_MAX_NAME_LEN]; + char value[SETTINGS_MAX_VAL_LEN]; + size_t val_len; +}; + +static struct setting_entry entries[CONFIG_SETTINGS_TFM_ITS_NUM_ENTRIES]; +static int entries_count; + +static int settings_its_load(struct settings_store *cs, const struct settings_load_arg *arg); +static int settings_its_save(struct settings_store *cs, const char *name, const char *value, + size_t val_len); + +static const struct settings_store_itf settings_its_itf = { + .csi_load = settings_its_load, + .csi_save = settings_its_save, +}; + +static struct settings_store default_settings_its = {.cs_itf = &settings_its_itf}; + +static int increment_uid(psa_storage_uid_t *uid) +{ + if (*uid < ZEPHYR_PSA_TFM_ITS_KEY_ID_RANGE_BEGIN || + *uid >= (ZEPHYR_PSA_TFM_ITS_KEY_ID_RANGE_BEGIN + + ZEPHYR_PSA_TFM_ITS_KEY_ID_RANGE_SIZE)) { + LOG_ERR("UID out of range! %lld > %d", *uid, + ZEPHYR_PSA_TFM_ITS_KEY_ID_RANGE_BEGIN + + ZEPHYR_PSA_TFM_ITS_KEY_ID_RANGE_SIZE); + return -EINVAL; + } + + (*uid)++; + return 0; +} + +static int store_entries(void) +{ + int err; + psa_status_t status; + psa_storage_uid_t uid = ZEPHYR_PSA_TFM_ITS_KEY_ID_RANGE_BEGIN; + size_t remaining = sizeof(entries); + size_t chunk_size = CONFIG_TFM_ITS_MAX_ASSET_SIZE; + const uint8_t *metadata_bytes = (const uint8_t *)&entries; + + /* + * Each ITS UID is treated like a sector. Data is written to each ITS node until + * that node is full, before incrementing the UID. This is done to minimize the + * number of allocated ITS nodes and to avoid wasting allocated bytes. + */ + while (remaining > 0) { + size_t write_size = (remaining > chunk_size) ? chunk_size : remaining; + + status = psa_its_set(uid, write_size, metadata_bytes, PSA_STORAGE_FLAG_NONE); + if (status) { + LOG_ERR("Error storing %d bytes of metadata! Bytes Remaining: %d, status: " + "%d", + write_size, remaining, status); + return status; + } + + metadata_bytes += write_size; + remaining -= write_size; + err = increment_uid(&uid); + if (err) { + return err; + } + } + + LOG_DBG("ITS entries stored successfully - bytes_saved: %d num_entries: %d max_uid: %lld", + sizeof(entries), entries_count, uid); + + return 0; +} + +static int load_entries(void) +{ + int err; + psa_status_t status; + size_t bytes_read; + psa_storage_uid_t uid = ZEPHYR_PSA_TFM_ITS_KEY_ID_RANGE_BEGIN; + size_t remaining = sizeof(entries); + size_t chunk_size = CONFIG_TFM_ITS_MAX_ASSET_SIZE; + uint8_t *metadata_bytes = (uint8_t *)&entries; + + /* + * Each ITS UID is treated like a sector. Data is written to each ITS node until + * that node is full, before incrementing the UID. This is done to minimize the + * number of allocated ITS nodes and to avoid wasting allocated bytes. + */ + while (remaining > 0) { + size_t to_read = (remaining > chunk_size) ? chunk_size : remaining; + + status = psa_its_get(uid, 0, to_read, metadata_bytes, &bytes_read); + if (status) { + return status; + } + + metadata_bytes += bytes_read; + remaining -= bytes_read; + err = increment_uid(&uid); + if (err) { + return err; + } + } + + for (int i = 0; i < CONFIG_SETTINGS_TFM_ITS_NUM_ENTRIES; i++) { + if (strnlen(entries[i].name, SETTINGS_MAX_NAME_LEN) != 0) { + entries_count++; + } + } + + LOG_DBG("ITS entries restored successfully - bytes_loaded: %d, num_entries: %d", + sizeof(entries), entries_count); + + return 0; +} + +/* void *back_end is the index of the entry in metadata entries struct */ +static ssize_t settings_its_read_fn(void *back_end, void *data, size_t len) +{ + LOG_DBG("ITS Read - index: %d", *(int *)back_end); + + if (*(int *)back_end < 0 || *(int *)back_end >= CONFIG_SETTINGS_TFM_ITS_NUM_ENTRIES) { + LOG_ERR("Invalid index %d in ITS metadata", *(int *)back_end); + return 0; + } + + memcpy(data, entries[*(int *)back_end].value, len); + + /* + * Callback expects return value of the number of bytes read + */ + return entries[*(int *)back_end].val_len; +} + +static int settings_its_load(struct settings_store *cs, const struct settings_load_arg *arg) +{ + int ret; + + for (int i = 0; i < entries_count; i++) { + + if (strnlen(entries[i].name, SETTINGS_MAX_NAME_LEN) != 0) { + + /* + * Pass the key to the settings handler with it's index as an argument, + * to be read during callback function later. + */ + ret = settings_call_set_handler(entries[i].name, entries[i].val_len, + settings_its_read_fn, (void *)&i, + (void *)arg); + if (ret) { + return ret; + } + } + } + + return 0; +} + +static int settings_its_save(struct settings_store *cs, const char *name, const char *value, + size_t val_len) +{ + if (entries_count >= CONFIG_SETTINGS_TFM_ITS_NUM_ENTRIES) { + LOG_ERR("%s: Max settings reached: %d", __func__, + CONFIG_SETTINGS_TFM_ITS_NUM_ENTRIES); + return -ENOMEM; + } + + if (val_len > SETTINGS_MAX_VAL_LEN) { + LOG_ERR("%s: Invalid settings size - val_len: %d", __func__, val_len); + return -EINVAL; + } + + int index; + + /* Search metadata to see if entry already exists */ + for (index = 0; index < CONFIG_SETTINGS_TFM_ITS_NUM_ENTRIES; index++) { + if (strncmp(entries[index].name, name, SETTINGS_MAX_NAME_LEN) == 0) { + break; + } else if (strnlen(entries[index].name, SETTINGS_MAX_NAME_LEN) == 0) { + /* New setting being entered */ + entries_count++; + break; + } + } + + LOG_DBG("ITS Save - index %d: name %s, val_len %d", index, name, val_len); + + /* Update metadata */ + strncpy(entries[index].name, name, SETTINGS_MAX_NAME_LEN); + memcpy(entries[index].value, value, val_len); + entries[index].val_len = val_len; + + k_work_schedule(&worker, K_MSEC(CONFIG_SETTINGS_TFM_ITS_LAZY_PERSIST_DELAY_MS)); + + return 0; +} + +void worker_persist_entries_struct_fn(struct k_work *work) +{ + k_mutex_lock(&worker_mutex, K_FOREVER); + store_entries(); + k_mutex_unlock(&worker_mutex); +} + +int settings_backend_init(void) +{ + psa_status_t status; + + /* Load ITS metadata */ + status = load_entries(); + + /* If resource DNE, we need to allocate it */ + if (status == PSA_ERROR_DOES_NOT_EXIST) { + status = store_entries(); + if (status) { + LOG_ERR("Error storing metadata in %s: (status %d)", __func__, status); + return -EIO; + } + } else if (status) { + LOG_ERR("Error loading metadata in %s: (status %d)", __func__, status); + return -EIO; + } + + settings_dst_register(&default_settings_its); + settings_src_register(&default_settings_its); + + k_work_init_delayable(&worker, worker_persist_entries_struct_fn); + + return 0; +} From c3ee626098942f4dce0f692a219e00d5dec04f3e Mon Sep 17 00:00:00 2001 From: Sean Kyer Date: Mon, 10 Feb 2025 16:24:32 -0800 Subject: [PATCH 2/3] tests: subsystem: settings: Add ITS backend tests Add ITS tests for ITS settings backend. Part of enabling settings subsystem for non-secure builds. Signed-off-by: Sean Kyer --- .../max32657evkit_max32657_ns.yaml | 1 + tests/subsys/settings/its/CMakeLists.txt | 9 ++ tests/subsys/settings/its/prj.conf | 12 ++ tests/subsys/settings/its/src/CMakeLists.txt | 14 ++ tests/subsys/settings/its/src/settings_test.h | 44 ++++++ .../settings/its/src/settings_test_its.c | 125 ++++++++++++++++++ tests/subsys/settings/its/testcase.yaml | 11 ++ 7 files changed, 216 insertions(+) create mode 100644 tests/subsys/settings/its/CMakeLists.txt create mode 100644 tests/subsys/settings/its/prj.conf create mode 100644 tests/subsys/settings/its/src/CMakeLists.txt create mode 100644 tests/subsys/settings/its/src/settings_test.h create mode 100644 tests/subsys/settings/its/src/settings_test_its.c create mode 100644 tests/subsys/settings/its/testcase.yaml diff --git a/boards/adi/max32657evkit/max32657evkit_max32657_ns.yaml b/boards/adi/max32657evkit/max32657evkit_max32657_ns.yaml index b8323e5aca87..33068ee5d75e 100644 --- a/boards/adi/max32657evkit/max32657evkit_max32657_ns.yaml +++ b/boards/adi/max32657evkit/max32657evkit_max32657_ns.yaml @@ -14,5 +14,6 @@ supported: - counter - pwm - spi + - its ram: 192 flash: 576 diff --git a/tests/subsys/settings/its/CMakeLists.txt b/tests/subsys/settings/its/CMakeLists.txt new file mode 100644 index 000000000000..877aa7be73de --- /dev/null +++ b/tests/subsys/settings/its/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2025 Analog Devices, Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(test_settings_its_raw) + +add_subdirectory(./src its_test_bindir) diff --git a/tests/subsys/settings/its/prj.conf b/tests/subsys/settings/its/prj.conf new file mode 100644 index 000000000000..7d9f4339bb6c --- /dev/null +++ b/tests/subsys/settings/its/prj.conf @@ -0,0 +1,12 @@ +# Copyright (c) 2025 Analog Devices, Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ZTEST=y +CONFIG_FLASH=y +CONFIG_FLASH_MAP=y +CONFIG_TFM_PARTITION_INTERNAL_TRUSTED_STORAGE=y +CONFIG_TFM_ITS_MAX_ASSET_SIZE_OVERRIDE=y +CONFIG_TFM_ITS_MAX_ASSET_SIZE=1024 +CONFIG_SETTINGS=y +CONFIG_SETTINGS_RUNTIME=y diff --git a/tests/subsys/settings/its/src/CMakeLists.txt b/tests/subsys/settings/its/src/CMakeLists.txt new file mode 100644 index 000000000000..38f6fc84848f --- /dev/null +++ b/tests/subsys/settings/its/src/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright (c) 2025 Analog Devices, Inc. +# Copyright (c) 2019 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories( + ${ZEPHYR_BASE}/subsys/settings/include + ${ZEPHYR_BASE}/subsys/settings/src + ${ZEPHYR_BASE}/tests/subsys/settings/its/src + ) + +target_sources(app PRIVATE settings_test_its.c) + +add_subdirectory(../../src settings_test_bindir) diff --git a/tests/subsys/settings/its/src/settings_test.h b/tests/subsys/settings/its/src/settings_test.h new file mode 100644 index 000000000000..a0c12b9e0cc0 --- /dev/null +++ b/tests/subsys/settings/its/src/settings_test.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 Analog Devices, Inc. + * Copyright (c) 2019 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _SETTINGS_TEST_ITS_H +#define _SETTINGS_TEST_ITS_H + +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint8_t val8; +extern uint8_t val8_un; +extern uint32_t val32; +extern uint64_t val64; + +extern int test_get_called; +extern int test_set_called; +extern int test_commit_called; +extern int test_export_block; + +extern struct settings_handler c_test_handlers[]; + +void ctest_clear_call_state(void); +int ctest_get_call_state(void); + +void config_wipe_srcs(void); +void *settings_config_setup(void); +void settings_config_teardown(void *fixture); + +#ifdef __cplusplus +} +#endif + +#endif /* _SETTINGS_TEST_ITS_H */ diff --git a/tests/subsys/settings/its/src/settings_test_its.c b/tests/subsys/settings/its/src/settings_test_its.c new file mode 100644 index 000000000000..3261e9ba2c65 --- /dev/null +++ b/tests/subsys/settings/its/src/settings_test_its.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2025 Analog Devices, Inc. + * Copyright (c) 2019 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include + +#include "settings_test.h" +#include "settings_priv.h" + +uint8_t val8; +uint8_t val8_un; +uint32_t val32; +uint64_t val64; + +int test_get_called; +int test_set_called; +int test_commit_called; +int test_export_block; + +int c1_handle_get(const char *name, char *val, int val_len_max); +int c1_handle_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg); +int c1_handle_commit(void); +int c1_handle_export(int (*cb)(const char *name, const void *value, size_t val_len)); + +struct settings_handler c_test_handlers[] = { + {.name = "myfoo", + .h_get = c1_handle_get, + .h_set = c1_handle_set, + .h_commit = c1_handle_commit, + .h_export = c1_handle_export}, +}; + +int c1_handle_get(const char *name, char *val, int val_len_max) +{ + const char *next; + + test_get_called = 1; + + if (settings_name_steq(name, "mybar", &next) && !next) { + memcpy(val, &val8, sizeof(val8)); + return val_len_max; + } + + if (settings_name_steq(name, "mybar64", &next) && !next) { + val_len_max = MIN(val_len_max, sizeof(val64)); + memcpy(val, &val64, val_len_max); + return val_len_max; + } + + return -ENOENT; +} + +int c1_handle_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) +{ + size_t val_len; + int rc; + const char *next; + + test_set_called = 1; + if (settings_name_steq(name, "mybar", &next) && !next) { + rc = read_cb(cb_arg, &val8, sizeof(val8)); + zassert_true(rc >= 0, "SETTINGS_VALUE_SET callback"); + return 0; + } + + if (settings_name_steq(name, "mybar64", &next) && !next) { + rc = read_cb(cb_arg, &val64, sizeof(val64)); + zassert_true(rc >= 0, "SETTINGS_VALUE_SET callback"); + return 0; + } + + if (settings_name_steq(name, "unaligned", &next) && !next) { + val_len = len; + zassert_equal(val_len, sizeof(val8_un), "value length: %d, ought equal 1", val_len); + rc = read_cb(cb_arg, &val8_un, sizeof(val8_un)); + zassert_true(rc >= 0, "SETTINGS_VALUE_SET callback"); + return 0; + } + + return -ENOENT; +} + +int c1_handle_commit(void) +{ + test_commit_called = 1; + return 0; +} + +int c1_handle_export(int (*cb)(const char *name, const void *value, size_t val_len)) +{ + if (test_export_block) { + return 0; + } + + (void)cb("myfoo/mybar", &val8, sizeof(val8)); + + (void)cb("myfoo/mybar64", &val64, sizeof(val64)); + + (void)cb("myfoo/unaligned", &val8_un, sizeof(val8_un)); + + return 0; +} + +void ctest_clear_call_state(void) +{ + test_get_called = 0; + test_set_called = 0; + test_commit_called = 0; +} + +int ctest_get_call_state(void) +{ + return test_get_called + test_set_called + test_commit_called; +} + +void config_wipe_srcs(void) +{ + sys_slist_init(&settings_load_srcs); + settings_save_dst = NULL; +} + +ZTEST_SUITE(settings_config, NULL, settings_config_setup, NULL, NULL, settings_config_teardown); diff --git a/tests/subsys/settings/its/testcase.yaml b/tests/subsys/settings/its/testcase.yaml new file mode 100644 index 000000000000..7202fae0231f --- /dev/null +++ b/tests/subsys/settings/its/testcase.yaml @@ -0,0 +1,11 @@ +# Copyright (c) 2025 Analog Devices, Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +tests: + settings.its: + depends_on: its + min_ram: 32 + tags: + - settings + - its From fa7b4b45d64f527f03b3465afb757d170da4a6b4 Mon Sep 17 00:00:00 2001 From: Sean Kyer Date: Mon, 24 Mar 2025 22:25:05 -0700 Subject: [PATCH 3/3] subsystem: settings: Add setting deletion to ITS backend Added the ability to remove settings when using the ITS backend settings subsystem. Signed-off-by: Sean Kyer --- include/zephyr/psa/key_ids.h | 4 +- subsys/settings/src/settings_its.c | 64 +++++++++++++++++++++++------- 2 files changed, 52 insertions(+), 16 deletions(-) diff --git a/include/zephyr/psa/key_ids.h b/include/zephyr/psa/key_ids.h index 91eb98d9bb5b..da955027c330 100644 --- a/include/zephyr/psa/key_ids.h +++ b/include/zephyr/psa/key_ids.h @@ -45,8 +45,8 @@ typedef uint32_t psa_key_id_t; #define ZEPHYR_PSA_WIFI_CREDENTIALS_KEY_ID_RANGE_SIZE 0x100 /* 256 */ /** PSA key ID range to be used by TF-M ITS */ -#define ZEPHYR_PSA_TFM_ITS_KEY_ID_RANGE_BEGIN (psa_key_id_t)0x20010100 -#define ZEPHYR_PSA_TFM_ITS_KEY_ID_RANGE_SIZE 0x10000 /* 64 Ki */ +#define ZEPHYR_PSA_SETTINGS_TFM_ITS_KEY_ID_RANGE_BEGIN (psa_key_id_t)0x20010100 +#define ZEPHYR_PSA_SETTINGS_TFM_ITS_KEY_ID_RANGE_SIZE 0x10000 /* 64 Ki */ /** PSA key ID range to be used by the end-user application. */ #define ZEPHYR_PSA_APPLICATION_KEY_ID_RANGE_BEGIN (psa_key_id_t)0x30000000 diff --git a/subsys/settings/src/settings_its.c b/subsys/settings/src/settings_its.c index 7ecf0acce620..e4d1e3d9c4ef 100644 --- a/subsys/settings/src/settings_its.c +++ b/subsys/settings/src/settings_its.c @@ -1,4 +1,6 @@ /* + * Copyright (c) 2019 Laczen + * Copyright (c) 2019 Nordic Semiconductor ASA * Copyright (c) 2025 Analog Devices, Inc. * * SPDX-License-Identifier: Apache-2.0 @@ -37,12 +39,10 @@ static struct settings_store default_settings_its = {.cs_itf = &settings_its_itf static int increment_uid(psa_storage_uid_t *uid) { - if (*uid < ZEPHYR_PSA_TFM_ITS_KEY_ID_RANGE_BEGIN || - *uid >= (ZEPHYR_PSA_TFM_ITS_KEY_ID_RANGE_BEGIN + - ZEPHYR_PSA_TFM_ITS_KEY_ID_RANGE_SIZE)) { - LOG_ERR("UID out of range! %lld > %d", *uid, - ZEPHYR_PSA_TFM_ITS_KEY_ID_RANGE_BEGIN + - ZEPHYR_PSA_TFM_ITS_KEY_ID_RANGE_SIZE); + if (*uid < ZEPHYR_PSA_SETTINGS_TFM_ITS_KEY_ID_RANGE_BEGIN || + *uid >= (ZEPHYR_PSA_SETTINGS_TFM_ITS_KEY_ID_RANGE_BEGIN + + ZEPHYR_PSA_SETTINGS_TFM_ITS_KEY_ID_RANGE_SIZE) - 1) { + LOG_ERR("UID out of range!"); return -EINVAL; } @@ -54,7 +54,7 @@ static int store_entries(void) { int err; psa_status_t status; - psa_storage_uid_t uid = ZEPHYR_PSA_TFM_ITS_KEY_ID_RANGE_BEGIN; + psa_storage_uid_t uid = ZEPHYR_PSA_SETTINGS_TFM_ITS_KEY_ID_RANGE_BEGIN; size_t remaining = sizeof(entries); size_t chunk_size = CONFIG_TFM_ITS_MAX_ASSET_SIZE; const uint8_t *metadata_bytes = (const uint8_t *)&entries; @@ -94,7 +94,7 @@ static int load_entries(void) int err; psa_status_t status; size_t bytes_read; - psa_storage_uid_t uid = ZEPHYR_PSA_TFM_ITS_KEY_ID_RANGE_BEGIN; + psa_storage_uid_t uid = ZEPHYR_PSA_SETTINGS_TFM_ITS_KEY_ID_RANGE_BEGIN; size_t remaining = sizeof(entries); size_t chunk_size = CONFIG_TFM_ITS_MAX_ASSET_SIZE; uint8_t *metadata_bytes = (uint8_t *)&entries; @@ -189,12 +189,30 @@ static int settings_its_save(struct settings_store *cs, const char *name, const } int index; + bool delete; - /* Search metadata to see if entry already exists */ + /* Find out if we are doing a delete */ + delete = ((value == NULL) || (val_len == 0)); + + /* Lock mutex before manipulating settings array */ + k_mutex_lock(&worker_mutex, K_FOREVER); + + /* + * Search metadata to see if entry already exists. Array is compacted, so first blank entry + * signals end of settings. + */ for (index = 0; index < CONFIG_SETTINGS_TFM_ITS_NUM_ENTRIES; index++) { if (strncmp(entries[index].name, name, SETTINGS_MAX_NAME_LEN) == 0) { break; - } else if (strnlen(entries[index].name, SETTINGS_MAX_NAME_LEN) == 0) { + } else if (entries[index].val_len == 0) { + + /* Setting already deleted */ + if (delete) { + LOG_DBG("%s: %s Already deleted!", __func__, name); + k_mutex_unlock(&worker_mutex); + return 0; + } + /* New setting being entered */ entries_count++; break; @@ -203,11 +221,29 @@ static int settings_its_save(struct settings_store *cs, const char *name, const LOG_DBG("ITS Save - index %d: name %s, val_len %d", index, name, val_len); - /* Update metadata */ - strncpy(entries[index].name, name, SETTINGS_MAX_NAME_LEN); - memcpy(entries[index].value, value, val_len); - entries[index].val_len = val_len; + if (delete) { + /* Clear metadata */ + memset(entries[index].name, 0, SETTINGS_MAX_NAME_LEN); + memset(entries[index].value, 0, SETTINGS_MAX_VAL_LEN); + entries[index].val_len = 0; + + /* If setting not at end of array, shift entries */ + if (index < entries_count - 1) { + memcpy(&entries[index], &entries[index + 1], + (entries_count - index - 1) * sizeof(struct setting_entry)); + /* Remove duplicate entry at end of array */ + memset(&entries[entries_count - 1], 0, sizeof(struct setting_entry)); + } + + entries_count--; + } else { + /* Update metadata */ + strncpy(entries[index].name, name, SETTINGS_MAX_NAME_LEN); + memcpy(entries[index].value, value, val_len); + entries[index].val_len = val_len; + } + k_mutex_unlock(&worker_mutex); k_work_schedule(&worker, K_MSEC(CONFIG_SETTINGS_TFM_ITS_LAZY_PERSIST_DELAY_MS)); return 0;