Skip to content

Commit 4493b39

Browse files
pacucha42espressif-bot
authored andcommitted
feat(storage): Added Block Device Layer support for esp_partition component
1 parent 46def99 commit 4493b39

20 files changed

+640
-46
lines changed
Lines changed: 47 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,67 @@
11
idf_build_get_property(esp_tee_build ESP_TEE_BUILD)
22

3+
set(reqs esp_blockdev)
4+
35
# bootloader build simplified version
46
if(BOOTLOADER_BUILD)
5-
set(srcs "partition_bootloader.c")
6-
set(reqs "spi_flash")
7-
set(priv_reqs "bootloader_support")
7+
set(srcs "partition_bootloader.c")
8+
list(APPEND reqs spi_flash)
9+
set(priv_reqs "bootloader_support")
810

9-
idf_component_register(SRCS "${srcs}"
10-
INCLUDE_DIRS "include"
11-
PRIV_INCLUDE_DIRS ${private_include_dirs}
12-
REQUIRES ${reqs}
13-
PRIV_REQUIRES ${priv_reqs})
11+
idf_component_register(SRCS "${srcs}"
12+
INCLUDE_DIRS "include"
13+
PRIV_INCLUDE_DIRS ${private_include_dirs}
14+
REQUIRES ${reqs}
15+
PRIV_REQUIRES ${priv_reqs})
1416

1517
# esp-tee build simplified version
1618
elseif(esp_tee_build)
17-
set(srcs "partition_tee.c")
18-
set(reqs "spi_flash")
19-
set(priv_reqs "tee_flash_mgr")
19+
set(srcs "partition_tee.c")
20+
list(APPEND reqs spi_flash)
21+
set(priv_reqs "tee_flash_mgr")
2022

21-
idf_component_register(SRCS "${srcs}"
22-
INCLUDE_DIRS "include"
23-
PRIV_INCLUDE_DIRS ${private_include_dirs}
24-
REQUIRES ${reqs}
25-
PRIV_REQUIRES ${priv_reqs})
23+
idf_component_register(SRCS "${srcs}"
24+
INCLUDE_DIRS "include"
25+
PRIV_INCLUDE_DIRS ${private_include_dirs}
26+
REQUIRES ${reqs}
27+
PRIV_REQUIRES ${priv_reqs})
2628

2729
# regular, OS build
2830
else()
29-
set(srcs "partition.c")
30-
set(priv_reqs esp_system spi_flash partition_table)
31-
set(reqs)
32-
set(private_include_dirs)
31+
set(srcs "partition.c")
32+
set(priv_reqs esp_system spi_flash partition_table)
33+
set(reqs esp_blockdev)
34+
set(private_include_dirs)
3335

34-
idf_build_get_property(build_dir BUILD_DIR)
35-
idf_build_get_property(target IDF_TARGET)
36+
idf_build_get_property(build_dir BUILD_DIR)
37+
idf_build_get_property(target IDF_TARGET)
3638

37-
if(${target} STREQUAL "linux")
38-
list(APPEND srcs "partition_linux.c")
39+
if(${target} STREQUAL "linux")
40+
list(APPEND srcs "partition_linux.c")
3941

40-
# Steal some include directories from bootloader_support components:
41-
idf_component_get_property(bootloader_support_dir bootloader_support COMPONENT_DIR)
42-
set(private_include_dirs ${bootloader_support_dir}/include)
43-
else()
44-
list(APPEND priv_reqs bootloader_support app_update)
45-
list(APPEND srcs "partition_target.c")
46-
endif()
42+
# Steal some include directories from bootloader_support components:
43+
idf_component_get_property(bootloader_support_dir bootloader_support COMPONENT_DIR)
44+
set(private_include_dirs ${bootloader_support_dir}/include)
45+
else()
46+
list(APPEND priv_reqs bootloader_support app_update)
47+
list(APPEND srcs "partition_target.c")
48+
endif()
4749

48-
idf_component_register(SRCS "${srcs}"
49-
INCLUDE_DIRS "include"
50-
PRIV_INCLUDE_DIRS ${private_include_dirs}
51-
REQUIRES ${reqs}
52-
PRIV_REQUIRES ${priv_reqs})
50+
idf_component_register(SRCS "${srcs}"
51+
INCLUDE_DIRS "include"
52+
PRIV_INCLUDE_DIRS ${private_include_dirs}
53+
REQUIRES ${reqs}
54+
PRIV_REQUIRES ${priv_reqs})
5355

54-
if(${target} STREQUAL "linux")
55-
# set BUILD_DIR because partition_linux.c uses a file created in the build directory
56-
target_compile_definitions(${COMPONENT_LIB} PRIVATE "BUILD_DIR=\"${build_dir}\"")
57-
endif()
56+
if(${target} STREQUAL "linux")
57+
# set BUILD_DIR because partition_linux.c uses a file created in the build directory
58+
target_compile_definitions(${COMPONENT_LIB} PRIVATE "BUILD_DIR=\"${build_dir}\"")
59+
endif()
5860

59-
if(CMAKE_C_COMPILER_ID MATCHES "GNU")
60-
# These flags are GCC specific
61-
set_property(SOURCE ${cache_srcs} APPEND_STRING PROPERTY COMPILE_FLAGS
62-
" -fno-inline-small-functions -fno-inline-functions-called-once")
63-
endif()
61+
if(CMAKE_C_COMPILER_ID MATCHES "GNU")
62+
# These flags are GCC specific
63+
set_property(SOURCE ${cache_srcs} APPEND_STRING PROPERTY COMPILE_FLAGS
64+
" -fno-inline-small-functions -fno-inline-functions-called-once")
65+
endif()
6466

6567
endif()

components/esp_partition/host_test/.build-test-rules.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,11 @@ components/esp_partition/host_test/partition_api_test:
77
depends_components:
88
- spi_flash
99
- esp_partition
10+
11+
components/esp_partition/host_test/partition_bdl_test:
12+
enable:
13+
- if: IDF_TARGET == "linux"
14+
reason: only test on linux
15+
depends_components:
16+
- spi_flash
17+
- esp_partition

components/esp_partition/host_test/partition_api_test/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
| Supported Targets | Linux |
22
| ----------------- | ----- |
33

4-
This is a test project for partition-related APIs on Linux target (CONFIG_IDF_TARGET_LINUX).
4+
This is a test project for verification of esp_partition component APIs on Linux target (CONFIG_IDF_TARGET_LINUX).
5+
It verifies all important APIs and properties, and prints the results.
6+
The Block-Device Layer tests have names with a prefix 'test_parition_bdl', available in 'components/esp_partition/host_test/partition_bdl_test', and the tests check all the BDL operations and commands related to 'esp_partition' (on host side)
57

68
# Build
79
Source the IDF environment as usual.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
cmake_minimum_required(VERSION 3.16)
2+
3+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
4+
set(COMPONENTS main)
5+
# Freertos is included via common components, however, currently only the mock component is compatible with linux
6+
# target.
7+
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/freertos/")
8+
9+
project(partition_bdl_test)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
| Supported Targets | Linux |
2+
| ----------------- | ----- |
3+
4+
This is a test project for esp_partition Block Device Layer interface on Linux target (CONFIG_IDF_TARGET_LINUX).
5+
6+
# Build
7+
Source the IDF environment as usual.
8+
9+
Once this is done, build the application:
10+
```bash
11+
idf.py build
12+
```
13+
14+
# Run
15+
```bash
16+
idf.py monitor
17+
```
18+
19+
The tests will be executed and the summary will be printed.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
idf_component_register(SRCS "partition_bdl_test.c"
2+
PRIV_REQUIRES esp_partition unity spi_flash)
3+
4+
# set BUILD_DIR because test uses a file created in the build directory
5+
target_compile_definitions(${COMPONENT_LIB} PRIVATE "BUILD_DIR=\"${build_dir}\"")
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Linux host partition API test
7+
*/
8+
9+
#include <string.h>
10+
#include <unistd.h>
11+
#include "esp_partition.h"
12+
#include "esp_private/partition_linux.h"
13+
#include "unity.h"
14+
#include "unity_fixture.h"
15+
16+
const char *TAG = "partition_bdl_test";
17+
18+
TEST_GROUP(partition_bdl);
19+
20+
TEST_SETUP(partition_bdl)
21+
{
22+
}
23+
24+
TEST_TEAR_DOWN(partition_bdl)
25+
{
26+
}
27+
28+
/* Test all the basic Block Device Layer APIs working correctly over emulated esp_partition instance.
29+
* NOR flash behavior expected.
30+
* */
31+
TEST(partition_bdl, test_partition_bdl_ops)
32+
{
33+
//get the block-device interface instance
34+
esp_blockdev_handle_t part_blockdev = NULL;
35+
TEST_ESP_OK(esp_partition_get_blockdev(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage1", &part_blockdev));
36+
37+
const size_t data_size = 256;
38+
uint8_t test_data[data_size];
39+
const off_t target_addr = 3*4*1024;
40+
uint8_t data_buffer[data_size];
41+
memset((void*)data_buffer, 0, data_size);
42+
43+
//erase the first sector data from the blockdev and check it's really wiped
44+
TEST_ESP_OK(part_blockdev->erase(part_blockdev, target_addr, part_blockdev->geometry.erase_size));
45+
memset((void*)test_data, 0xFF, data_size); //erased NOR flash sector contains only 1s
46+
47+
TEST_ESP_OK(part_blockdev->read(part_blockdev, data_buffer, sizeof(data_buffer), target_addr, data_size));
48+
TEST_ASSERT_EQUAL(0, memcmp(test_data, data_buffer, data_size));
49+
50+
//write to the blockdev
51+
memset((void*)test_data, 'A', data_size);
52+
TEST_ESP_OK(part_blockdev->write(part_blockdev, test_data, target_addr, data_size));
53+
54+
//read from the blockdev the data written before
55+
TEST_ESP_OK(part_blockdev->read(part_blockdev, data_buffer, sizeof(data_buffer), target_addr, data_size));
56+
TEST_ASSERT_EQUAL(0, memcmp(test_data, data_buffer, data_size));
57+
58+
//release the BDL object - nothing to check here, the BDL memory is just freed
59+
esp_partition_release_blockdev(part_blockdev);
60+
}
61+
62+
/* Test parallel access to two independent partitions through BDL interface.
63+
* Use both 'esp_partition_t' and type-subtype-label BDL getters.
64+
* NOR flash behavior expected.
65+
* */
66+
TEST(partition_bdl, test_two_partitions_bdl_ops)
67+
{
68+
//get the block-device interface instance for partition 'storage1'
69+
esp_blockdev_handle_t part_blockdev_1 = NULL;
70+
TEST_ESP_OK(esp_partition_get_blockdev(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage1", &part_blockdev_1));
71+
72+
//get pointer to esp_partition_t object for partition 'storage2'
73+
esp_partition_iterator_t iter = esp_partition_find(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage2");
74+
TEST_ASSERT_NOT_NULL(iter);
75+
esp_partition_t *part = (esp_partition_t*)esp_partition_get(iter);
76+
TEST_ASSERT_NOT_NULL(part);
77+
esp_partition_iterator_release(iter);
78+
79+
esp_blockdev_handle_t part_blockdev_2 = NULL;
80+
TEST_ESP_OK(esp_partition_ptr_get_blockdev(part, &part_blockdev_2));
81+
82+
//erase & write & read data on both partitions in parallel
83+
const size_t data_size = 256;
84+
uint8_t test_data[data_size];
85+
const off_t target_addr = 3*4*1024;
86+
uint8_t data_buffer_1[data_size];
87+
uint8_t data_buffer_2[data_size];
88+
memset((void*)data_buffer_1, 0, data_size);
89+
memset((void*)data_buffer_2, 0, data_size);
90+
91+
//erase the first sector data from the blockdev and check it's really wiped
92+
TEST_ESP_OK(part_blockdev_1->erase(part_blockdev_1, target_addr, part_blockdev_1->geometry.erase_size));
93+
TEST_ESP_OK(part_blockdev_2->erase(part_blockdev_2, target_addr, part_blockdev_2->geometry.erase_size));
94+
memset((void*)test_data, 0xFF, data_size); //erased NOR flash sector contains only 1s
95+
96+
TEST_ESP_OK(part_blockdev_1->read(part_blockdev_1, data_buffer_1, sizeof(data_buffer_1), target_addr, data_size));
97+
TEST_ESP_OK(part_blockdev_2->read(part_blockdev_2, data_buffer_2, sizeof(data_buffer_2), target_addr, data_size));
98+
TEST_ASSERT_EQUAL(0, memcmp(test_data, data_buffer_1, data_size));
99+
TEST_ASSERT_EQUAL(0, memcmp(test_data, data_buffer_2, data_size));
100+
101+
//write to the blockdev 1
102+
memset((void*)test_data, 'A', data_size);
103+
TEST_ESP_OK(part_blockdev_1->write(part_blockdev_1, test_data, target_addr, data_size));
104+
105+
//read the data written before from the blockdev 1
106+
TEST_ESP_OK(part_blockdev_1->read(part_blockdev_1, data_buffer_1, sizeof(data_buffer_1), target_addr, data_size));
107+
TEST_ASSERT_EQUAL(0, memcmp(test_data, data_buffer_1, data_size));
108+
109+
//write to the blockdev 2
110+
memset((void*)test_data, 'B', data_size);
111+
TEST_ESP_OK(part_blockdev_2->write(part_blockdev_2, test_data, target_addr, data_size));
112+
113+
//read the data written before from the blockdev 2
114+
TEST_ESP_OK(part_blockdev_2->read(part_blockdev_2, data_buffer_2, sizeof(data_buffer_2), target_addr, data_size));
115+
TEST_ASSERT_EQUAL(0, memcmp(test_data, data_buffer_2, data_size));
116+
117+
//release the BDL object - nothing to check here, the BDL memory is just freed
118+
esp_partition_release_blockdev(part_blockdev_1);
119+
esp_partition_release_blockdev(part_blockdev_2);
120+
}
121+
122+
TEST_GROUP_RUNNER(partition_bdl)
123+
{
124+
RUN_TEST_CASE(partition_bdl, test_partition_bdl_ops);
125+
RUN_TEST_CASE(partition_bdl, test_two_partitions_bdl_ops);
126+
}
127+
128+
static void run_all_tests(void)
129+
{
130+
RUN_TEST_GROUP(partition_bdl);
131+
}
132+
133+
int main(int argc, char **argv)
134+
{
135+
UNITY_MAIN_FUNC(run_all_tests);
136+
return 0;
137+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Name, Type, SubType, Offset, Size, Flags
2+
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3+
nvs, data, nvs, 0x9000, 0x6000,
4+
phy_init, data, phy, 0xf000, 0x1000,
5+
factory, app, factory, 0x10000, 1M,
6+
storage1, data, , 0x110000, 512K
7+
storage2, data, , 0x190000, 512K,
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
2+
# SPDX-License-Identifier: Unlicense OR CC0-1.0
3+
import pytest
4+
from pytest_embedded import Dut
5+
from pytest_embedded_idf.utils import idf_parametrize
6+
7+
8+
@pytest.mark.host_test
9+
@idf_parametrize('target', ['linux'], indirect=['target'])
10+
def test_esp_partition_bdl(dut: Dut) -> None:
11+
dut.expect_unity_test_output(timeout=5)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CONFIG_IDF_TARGET="linux"
2+
CONFIG_IDF_TARGET_LINUX=y
3+
CONFIG_COMPILER_CXX_EXCEPTIONS=y
4+
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n
5+
CONFIG_UNITY_ENABLE_FIXTURE=y
6+
CONFIG_PARTITION_TABLE_CUSTOM=y
7+
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partition_table.csv"
8+
CONFIG_ESP_PARTITION_ENABLE_STATS=y

0 commit comments

Comments
 (0)