From 039d8ed9142597321a7a385eaa41450a1cc221ff Mon Sep 17 00:00:00 2001 From: Laczen JMS Date: Fri, 5 Apr 2024 18:04:14 +0200 Subject: [PATCH 1/2] flash_partitions: a flash_map alternative Working with partitions on a flash device has been done using the flash_map subsystem. The flash_map subsystem has been limiting (e.g. #52395) and does not support support for flash devices that do not need an erase (non flash devices that are supported as if they are flash). The PR proposes an alternative for flash_map that supports classic flash devices, "no-erase" flash devices. Partitions can be read-only, and it is possible to provide an "override" erase-block-size. The support for "no-erase" flash devices is achieved by the definition of a "zephyr,flash-no-erase" compatible that is added to the flash device. Signed-off-by: Laczen JMS --- dts/bindings/misc/zephyr,flash-no-erase.yaml | 6 + .../misc/zephyr,flash-partitions.yaml | 99 +++++++ include/zephyr/storage/flash_partitions.h | 186 ++++++++++++ subsys/storage/CMakeLists.txt | 1 + subsys/storage/Kconfig | 1 + .../storage/flash_partitions/CMakeLists.txt | 4 + subsys/storage/flash_partitions/Kconfig | 31 ++ .../flash_partitions/flash_partitions.c | 265 ++++++++++++++++++ 8 files changed, 593 insertions(+) create mode 100644 dts/bindings/misc/zephyr,flash-no-erase.yaml create mode 100644 dts/bindings/misc/zephyr,flash-partitions.yaml create mode 100644 include/zephyr/storage/flash_partitions.h create mode 100644 subsys/storage/flash_partitions/CMakeLists.txt create mode 100644 subsys/storage/flash_partitions/Kconfig create mode 100644 subsys/storage/flash_partitions/flash_partitions.c diff --git a/dts/bindings/misc/zephyr,flash-no-erase.yaml b/dts/bindings/misc/zephyr,flash-no-erase.yaml new file mode 100644 index 00000000000000..9f81cea8b84dc4 --- /dev/null +++ b/dts/bindings/misc/zephyr,flash-no-erase.yaml @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Laczen +# SPDX-License-Identifier: Apache-2.0 + +description: Compatible describing that a flash device has no erase. + +compatible: "zephyr,flash-no-erase" diff --git a/dts/bindings/misc/zephyr,flash-partitions.yaml b/dts/bindings/misc/zephyr,flash-partitions.yaml new file mode 100644 index 00000000000000..6462f8232b0177 --- /dev/null +++ b/dts/bindings/misc/zephyr,flash-partitions.yaml @@ -0,0 +1,99 @@ +description: | + This binding is used to describe fixed partitions of a flash memory. + + Here is an example: + + &flash0 { + partitions { + compatible = "zephyr,flash-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x0000C000>; + }; + slot0_partition: partition@c000 { + label = "image-0"; + reg = <0x0000C000 0x00076000>; + }; + slot1_partition: partition@82000 { + label = "image-1"; + reg = <0x00082000 0x00076000>; + }; + + /* + * The flash starting at 0x000f8000 and ending at + * 0x000fffff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@f8000 { + label = "storage"; + reg = <0x000f8000 0x00008000>; + }; + }; + }; + + Note that the usual name for this node is 'partitions'. + The zephyr,flash-partitions node should be a child of the flash + memory node. Note also that the flash memory node is usually + different from the node representing the flash controller + IP block. + + Above, slot0_partition's register address 0xc000 means that + the partition begins at that offset from the parent flash + memory flash0's base address. That is, partition addresses + are relative; physical addresses must be calculated by adding + the start address of flash0 in memory to each partition's + reg address. + +compatible: "zephyr,flash-partitions" + +properties: + "#address-cells": + type: int + description: | + Number of cells required to represent a child node's + reg property address. This must be large enough to + represent the start offset of each partition. + + "#size-cells": + type: int + description: | + Number of cells required to represent a child node's + reg property address. This must be large enough to + represent the size of each partition in bytes. + +child-binding: + description: | + Each child node of the zephyr,flash-partitions node represents + an individual flash partition. These should usually + look like this: + + partition_nodelabel: partition@START_OFFSET { + label = "human-readable-name"; + reg = <0xSTART_OFFSET 0xSIZE>; + }; + properties: + label: + type: string + description: | + Human readable string describing the flash partition. + read-only: + type: boolean + description: set this property if the partition is read-only + erase-block-size: + type: int + description: override value for the flash node erase-block-size. + reg: + type: array + description: | + This should be in the format , where OFFSET + is the offset of the flash partition relative to the base + address of the parent memory, and SIZE is the size of + the partition in bytes. + required: true diff --git a/include/zephyr/storage/flash_partitions.h b/include/zephyr/storage/flash_partitions.h new file mode 100644 index 00000000000000..10c878c5810672 --- /dev/null +++ b/include/zephyr/storage/flash_partitions.h @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2024 Laczen + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief Public API for flash partitions + */ + +#ifndef ZEPHYR_INCLUDE_FLASH_PARTITIONS_H_ +#define ZEPHYR_INCLUDE_FLASH_PARTITIONS_H_ + +/** + * @brief Abstraction over flash memory and its partitions + * + * @defgroup flash_partitions_api flash_partitions interface + * @{ + */ + +/* + * This API makes it possible to operate on flash partitions easily and + * effectively. + */ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The flash_partitions subsystem provide an abstraction layer between flash + * memory specific drivers and higher-level applications for flash memory + * partitions. On flash partitions the following routines for operation are + * provided: open, read, write, erase, clear and close. + * + */ + +/** + * @brief Retrieve a pointer to the flash partition info struct. + * + * A flash partition with nodelabel "nodelabel" is retrieved as: + * const struct flash_partition *fp = FLASH_PARTITION_GET(nodelabel) + * + * @param nodelabel of the flash partition. + */ +#define FLASH_PARTITION_GET(nodelabel) \ + &UTIL_CAT(flash_partition_, DT_NODELABEL(nodelabel)) + +/** + * @brief flash_partition represents a flash partition. + */ +struct flash_partition { + /** flash device */ + const struct device *fldev; + /** flash partition size */ + const size_t size; + /** flash partition offset on flash device */ + const size_t offset; + /** flash partition erase-block-size */ + const size_t erase_block_size; + /** flash partition routines */ + int (*const open)(const struct flash_partition *partition); + int (*const read)(const struct flash_partition *partition, size_t start, + void *data, size_t len); + int (*const write)(const struct flash_partition *partition, size_t start, + const void *data, size_t len); + int (*const erase)(const struct flash_partition *partition, size_t start, + size_t len); + int (*const close)(const struct flash_partition *partition); +#if CONFIG_FLASH_PARTITIONS_LABELS + const char *label; +#endif +}; + +/** + * @brief Get the size in byte of a flash partition. + * + * @param[in] partition flash partition + * @return the size. + */ +size_t flash_partition_get_size(const struct flash_partition *partition); + +/** + * @brief Get the erase-block-size in byte of a flash partition. + * + * @param[in] partition flash partition + * @return the size. + */ +size_t flash_partition_get_ebs(const struct flash_partition *partition); + +/** + * @brief Get the label a flash partition. + * + * @param[in] partition flash partition + * @param[out] label + * @return the size. + */ +const char *flash_partition_get_label(const struct flash_partition *partition); + +/** + * @brief Open a flash partition. + * + * @param[in] partition flash partition + * + * @return 0 on success, negative errno code on fail. + */ +int flash_partition_open(const struct flash_partition *partition); + +/** + * @brief Read data from flash partition. Read boundaries are verified before + * read request is executed. + * + * + * @param[in] partition flash partition + * @param[in] start point relative from beginning of flash partition + * @param[out] data Buffer to store read data + * @param[in] len Size to read + * + * @return 0 on success, negative errno code on fail. + */ +int flash_partition_read(const struct flash_partition *partition, size_t start, + void *data, size_t len); + +/** + * @brief Write data to flash partition. Write boundaries are verified before + * write request is executed. + * + * @param[in] partition flash partition + * @param[in] start point relative from beginning of flash partition + * @param[out] data Buffer with data to be written + * @param[in] len Size to read + * + * @return 0 on success, negative errno code on fail. + */ +int flash_partition_write(const struct flash_partition *partition, size_t start, + const void *data, size_t len); + +/** + * @brief Erase range on flash partition. Erase boundaries are verified before + * erase is executed. + * + * @param[in] partition flash partition + * @param[in] start point relative from beginning of flash partition + * @param[in] len Size to erase + * + * @return 0 on success, negative errno code on fail. + */ +int flash_partition_erase(const struct flash_partition *partition, size_t start, + size_t len); + +/** + * @brief Close a flash partition. + * + * @param[in] partition flash partition + * + * @return 0 on success, negative errno code on fail. + */ +int flash_partition_close(const struct flash_partition *partition); + +/** @cond INTERNAL_HIDDEN */ + +#define FLASH_PARTITION_DECLARE(n) \ + extern const struct flash_partition flash_partition_##n; + +#define FLASH_PARTITIONS_DECLARE(inst) \ + DT_FOREACH_CHILD_STATUS_OKAY(inst, FLASH_PARTITION_DECLARE) + +DT_FOREACH_STATUS_OKAY(zephyr_flash_partitions, FLASH_PARTITIONS_DECLARE) +/** @endcond */ + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif /* ZEPHYR_INCLUDE_FLASH_PARTITIONS_H_ */ diff --git a/subsys/storage/CMakeLists.txt b/subsys/storage/CMakeLists.txt index ed94d1920ba0b6..0f15fdc72e5a49 100644 --- a/subsys/storage/CMakeLists.txt +++ b/subsys/storage/CMakeLists.txt @@ -1,4 +1,5 @@ # SPDX-License-Identifier: Apache-2.0 add_subdirectory_ifdef(CONFIG_FLASH_MAP flash_map) +add_subdirectory_ifdef(CONFIG_FLASH_PARTITIONS flash_partitions) add_subdirectory_ifdef(CONFIG_STREAM_FLASH stream) diff --git a/subsys/storage/Kconfig b/subsys/storage/Kconfig index 6d78778449ce62..7ec7b768854225 100644 --- a/subsys/storage/Kconfig +++ b/subsys/storage/Kconfig @@ -6,6 +6,7 @@ menu "Storage" source "subsys/storage/flash_map/Kconfig" +source "subsys/storage/flash_partitions/Kconfig" source "subsys/storage/stream/Kconfig" endmenu diff --git a/subsys/storage/flash_partitions/CMakeLists.txt b/subsys/storage/flash_partitions/CMakeLists.txt new file mode 100644 index 00000000000000..1abb81c63f38cb --- /dev/null +++ b/subsys/storage/flash_partitions/CMakeLists.txt @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() +zephyr_library_sources(flash_partitions.c) diff --git a/subsys/storage/flash_partitions/Kconfig b/subsys/storage/flash_partitions/Kconfig new file mode 100644 index 00000000000000..f8d54dbcf20a93 --- /dev/null +++ b/subsys/storage/flash_partitions/Kconfig @@ -0,0 +1,31 @@ +# Copyright (c) 2024, Laczen +# SPDX-License-Identifier: Apache-2.0 + +menuconfig FLASH_PARTITIONS + bool "flash partitions support" + default y if DT_HAS_ZEPHYR_FLASH_PARTITIONS_ENABLED + select FLASH + help + Enables support for the flash partitions system, which enables using + unified routines to work with partitions defined on flash devices. + +if FLASH_PARTITIONS + +config FLASH_PARTITIONS_RUNTIME_VERIFY + bool "runtime verification of erase-block-size" + select FLASH_PAGE_LAYOUT + help + Enable runtime verification that erase-block-size is a multiple of the + flash erase block size. + +config FLASH_PARTITIONS_LABELS + bool "Access flash partition labels at runtime" + help + If enabled the label property of the flash partitions can be retrieved + at runtime. + +module = FLASH_PARTITIONS +module-str = flash_partitions +source "subsys/logging/Kconfig.template.log_config" + +endif #FLASH_PARTITIONS diff --git a/subsys/storage/flash_partitions/flash_partitions.c b/subsys/storage/flash_partitions/flash_partitions.c new file mode 100644 index 00000000000000..9276342a32f35c --- /dev/null +++ b/subsys/storage/flash_partitions/flash_partitions.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2024, Laczen + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +LOG_MODULE_REGISTER(flash_partitions, CONFIG_FLASH_PARTITIONS_LOG_LEVEL); + +size_t flash_partition_get_size(const struct flash_partition *partition) +{ + if (partition == NULL) { + return 0U; + } + + return partition->size; +} + +size_t flash_partition_get_ebs(const struct flash_partition *partition) +{ + if (partition == NULL) { + return 0U; + } + + return partition->erase_block_size; +} + +const char *flash_partition_get_label(const struct flash_partition *partition) +{ +#if CONFIG_FLASH_PARTITIONS_LABELS + return partition->label; +#else + return NULL; +#endif +} + +int flash_partition_open(const struct flash_partition *partition) +{ + int rc; + + if (partition == NULL) { + rc = -EINVAL; + goto end; + } + + if (partition->open == NULL) { + rc = -ENOTSUP; + goto end; + } + + rc = partition->open(partition); +end: + LOG_DBG("open: [%d]", rc); + return rc; +} + +int flash_partition_read(const struct flash_partition *partition, size_t start, + void *data, size_t len) +{ + int rc; + + if (partition == NULL) { + rc = -EINVAL; + goto end; + } + + if (partition->read == NULL) { + rc = -ENOTSUP; + goto end; + } + + if ((start + len) > partition->size) { + rc = -EINVAL; + goto end; + } + + rc = partition->read(partition, partition->offset + start, data, len); +end: + LOG_DBG("read %d byte at 0x%x: [%d]", len, start, rc); + return rc; +} + +int flash_partition_write(const struct flash_partition *partition, size_t start, + const void *data, size_t len) +{ + int rc; + + if (partition == NULL) { + rc = -EINVAL; + goto end; + } + + if (partition->write == NULL) { + rc = -ENOTSUP; + goto end; + } + + if ((start + len) > partition->size) { + rc = -EINVAL; + goto end; + } + + rc = partition->write(partition, partition->offset + start, data, len); +end: + LOG_DBG("write %d byte at 0x%x: [%d]", len, start, rc); + return rc; +} + +int flash_partition_erase(const struct flash_partition *partition, size_t start, + size_t len) +{ + int rc; + + if (partition == NULL) { + rc = -EINVAL; + goto end; + } + + if (partition->erase == NULL) { + rc = -ENOTSUP; + goto end; + } + + if ((start + len) > partition->size) { + rc = -EINVAL; + goto end; + } + + rc = partition->erase(partition, partition->offset + start, len); +end: + LOG_DBG("erase %d byte at 0x%x: [%d]", len, start, rc); + return rc; +} + +int flash_partition_close(const struct flash_partition *partition) +{ + int rc; + + if (partition == NULL) { + rc = -EINVAL; + goto end; + } + + if (partition->close == NULL) { + rc = -ENOTSUP; + goto end; + } + + rc = partition->close(partition); +end: + LOG_DBG("close: [%d]", rc); + return rc; +} + +static int fp_open(const struct flash_partition *partition) +{ + int rc = 0; + + if (!device_is_ready(partition->fldev)) { + rc = -ENODEV; + goto end; + } + + if (IS_ENABLED(CONFIG_FLASH_PARTITIONS_RUNTIME_VERIFY)) { + const size_t end = partition->offset + partition->size; + struct flash_pages_info page = { + .start_offset = (off_t)partition->offset, + }; + + while (page.start_offset < end) { + rc = flash_get_page_info_by_offs( + partition->fldev, page.start_offset, &page); + if (rc != 0) { + LOG_ERR("failed to get flash page info"); + break; + } + + if ((partition->erase_block_size % page.size) != 0U) { + LOG_ERR("erase-block-size configuration error"); + rc = -EINVAL; + break; + } + + page.start_offset += page.size; + } + } +end: + return rc; +} + +static int fp_read(const struct flash_partition *partition, size_t start, + void *data, size_t len) +{ + return flash_read(partition->fldev, (off_t)start, data, len); +} + +static int fp_write(const struct flash_partition *partition, size_t start, + const void *data, size_t len) +{ + return flash_write(partition->fldev, (off_t)start, data, len); +} + +static int fp_erase(const struct flash_partition *partition, size_t start, + size_t len) +{ + return flash_erase(partition->fldev, (off_t)start, len); +} + +static int fp_close(const struct flash_partition *partition) +{ + return 0; +} + +#define FLASH_PARTITION_SIZE(inst) DT_REG_SIZE(inst) +#define FLASH_PARTITION_OFF(inst) DT_REG_ADDR(inst) +#define FLASH_PARTITION_GPDEV(inst) \ + COND_CODE_1(DT_NODE_HAS_COMPAT(inst, soc_nv_flash), \ + (DEVICE_DT_GET(DT_PARENT(inst))), (DEVICE_DT_GET(inst))) +#define FLASH_PARTITION_DEV(inst) FLASH_PARTITION_GPDEV(DT_GPARENT(inst)) +#define FLASH_PARTITION_EBS(inst) \ + DT_PROP_OR(inst, erase_block_size, \ + (DT_PROP_OR(DT_GPARENT(inst), erase_block_size, \ + (FLASH_PARTITION_SIZE(inst))))) +#define FLASH_PARTITION_WRITE_DISABLE(inst) DT_PROP_OR(inst, read_only, false) +#define FLASH_PARTITION_ERASE_DISABLE(inst) \ + DT_PROP_OR(inst, read_only, false) || \ + DT_NODE_HAS_COMPAT(DT_GPARENT(inst), zephyr_flash_no_erase) +#define FLASH_PARTITION_LABEL(inst) DT_PROP_OR(inst, label, NULL) + +#if CONFIG_FLASH_PARTITIONS_LABELS +#define FLASH_PARTITION_DEFINE(inst) \ + const struct flash_partition flash_partition_##inst = { \ + .fldev = FLASH_PARTITION_DEV(inst), \ + .size = FLASH_PARTITION_SIZE(inst), \ + .offset = FLASH_PARTITION_OFF(inst), \ + .erase_block_size = FLASH_PARTITION_EBS(inst), \ + .open = fp_open, \ + .read = fp_read, \ + .write = FLASH_PARTITION_WRITE_DISABLE(inst) ? NULL : fp_write, \ + .erase = FLASH_PARTITION_ERASE_DISABLE(inst) ? NULL : fp_erase, \ + .close = fp_close, \ + .label = FLASH_PARTITION_LABEL(inst), \ + }; +#else +#define FLASH_PARTITION_DEFINE(inst) \ + const struct flash_partition flash_partition_##inst = { \ + .fldev = FLASH_PARTITION_DEV(inst), \ + .size = FLASH_PARTITION_SIZE(inst), \ + .offset = FLASH_PARTITION_OFF(inst), \ + .erase_block_size = FLASH_PARTITION_EBS(inst), \ + .open = fp_open, \ + .read = fp_read, \ + .write = FLASH_PARTITION_WRITE_DISABLE(inst) ? NULL : fp_write, \ + .erase = FLASH_PARTITION_ERASE_DISABLE(inst) ? NULL : fp_erase, \ + .close = fp_close, \ + }; +#endif + +#define FLASH_PARTITIONS_DEFINE(inst) \ + DT_FOREACH_CHILD(inst, FLASH_PARTITION_DEFINE) + +DT_FOREACH_STATUS_OKAY(zephyr_flash_partitions, FLASH_PARTITIONS_DEFINE) From d56249a9f546eedf2fddc0c76010da8ee9737089 Mon Sep 17 00:00:00 2001 From: Laczen JMS Date: Sat, 6 Apr 2024 11:07:38 +0200 Subject: [PATCH 2/2] flash_partitions: add tests Add tests for the flash_partitions subsystem Signed-off-by: Laczen JMS --- .../storage/flash_partitions/CMakeLists.txt | 9 +++ .../boards/native_sim.overlay | 24 +++++++ .../subsys/storage/flash_partitions/prj.conf | 6 ++ .../storage/flash_partitions/src/main.c | 72 +++++++++++++++++++ .../storage/flash_partitions/testcase.yaml | 10 +++ 5 files changed, 121 insertions(+) create mode 100644 tests/subsys/storage/flash_partitions/CMakeLists.txt create mode 100644 tests/subsys/storage/flash_partitions/boards/native_sim.overlay create mode 100644 tests/subsys/storage/flash_partitions/prj.conf create mode 100644 tests/subsys/storage/flash_partitions/src/main.c create mode 100644 tests/subsys/storage/flash_partitions/testcase.yaml diff --git a/tests/subsys/storage/flash_partitions/CMakeLists.txt b/tests/subsys/storage/flash_partitions/CMakeLists.txt new file mode 100644 index 00000000000000..8048e44459f81b --- /dev/null +++ b/tests/subsys/storage/flash_partitions/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Laczen +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(flash_partitions_test) + +target_sources(app PRIVATE src/main.c) diff --git a/tests/subsys/storage/flash_partitions/boards/native_sim.overlay b/tests/subsys/storage/flash_partitions/boards/native_sim.overlay new file mode 100644 index 00000000000000..ef33c78fed23f1 --- /dev/null +++ b/tests/subsys/storage/flash_partitions/boards/native_sim.overlay @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 Laczen + * SPDX-License-Identifier: Apache-2.0 + */ + +&flash0 { + compatible = "soc-nv-flash", "zephyr,flash-no-erase"; + + flash_partitions { + compatible = "zephyr,flash-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + flash0_partition0: partition@0 { + reg = <0x00000000 0x00002000>; + erase-block-size = ; + read-only; + }; + + flash0_partition1: partition@2000 { + reg = <0x00002000 0x00002000>; + }; + }; +}; diff --git a/tests/subsys/storage/flash_partitions/prj.conf b/tests/subsys/storage/flash_partitions/prj.conf new file mode 100644 index 00000000000000..45d2ccee4fe5c6 --- /dev/null +++ b/tests/subsys/storage/flash_partitions/prj.conf @@ -0,0 +1,6 @@ +# Copyright (c) 2024 Laczen +# SPDX-License-Identifier: Apache-2.0 +CONFIG_FLASH_PARTITIONS=y +CONFIG_FLASH_PARTITIONS_RUNTIME_VERIFY=y +CONFIG_USERSPACE=n +CONFIG_ZTEST=y diff --git a/tests/subsys/storage/flash_partitions/src/main.c b/tests/subsys/storage/flash_partitions/src/main.c new file mode 100644 index 00000000000000..7e3ddb2a5c7f4d --- /dev/null +++ b/tests/subsys/storage/flash_partitions/src/main.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2024 Laczen. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#define FLASH_PARTITION0 flash0_partition0 +#define FLASH_PARTITION1 flash0_partition1 + +ZTEST_BMEM static const struct flash_partition *fp; + +static void *flash_partition_api_setup(void) +{ + return NULL; +} + +ZTEST_USER(flash_partition_api, test_read_write_erase) +{ + uint8_t *wr = "/a9/9a/a9/9a"; + uint8_t rd[sizeof(wr)]; + int rc = 0; + + memset(rd, 0, sizeof(rd)); + + rc = flash_partition_open(fp); + zassert_equal(rc, 0, "open returned [%d]", rc); + + TC_PRINT("flash partition: size %d, offset %d, erase-block-size %d\n", + fp->size, fp->offset, fp->erase_block_size); + + rc = flash_partition_read(fp, 0, rd, sizeof(rd)); + zassert_equal(rc, 0, "read returned [%d]", rc); + + if (fp->write != NULL) { + rc = flash_partition_write(fp, 0, wr, sizeof(wr)); + zassert_equal(rc, 0, "write returned [%d]", rc); + + rc = flash_partition_read(fp, 0, rd, sizeof(rd)); + zassert_equal(rc, 0, "read returned [%d]", rc); + + zassert_equal(memcmp(wr, rd, sizeof(rd)), 0, + "read/write data differ"); + } + + if (fp->erase != NULL) { + rc = flash_partition_erase(fp, 0, fp->erase_block_size); + zassert_equal(rc, 0, "erase returned [%d]", rc); + } else { + TC_PRINT("no erase\n"); + } +} + +ZTEST_SUITE(flash_partition_api, NULL, flash_partition_api_setup, NULL, NULL, + NULL); + +/* Run all of our tests on the given flash partition */ +static void run_tests_on_partition(const struct flash_partition *partition) +{ + fp = partition; + ztest_run_all(NULL, false, 1, 1); +} + +void test_main(void) +{ + run_tests_on_partition(FLASH_PARTITION_GET(FLASH_PARTITION0)); + run_tests_on_partition(FLASH_PARTITION_GET(FLASH_PARTITION1)); + ztest_verify_all_test_suites_ran(); +} diff --git a/tests/subsys/storage/flash_partitions/testcase.yaml b/tests/subsys/storage/flash_partitions/testcase.yaml new file mode 100644 index 00000000000000..c226bedf479d04 --- /dev/null +++ b/tests/subsys/storage/flash_partitions/testcase.yaml @@ -0,0 +1,10 @@ +common: + depends_on: + - flash_partitions + - flash + tags: flash_partitions +tests: + storage.flash_partitions.native_sim.api: + platform_allow: + - native_sim + timeout: 60