Skip to content

Commit ab46817

Browse files
committed
SFDP: Add unit tests for Sector Map Parameter Table parsing
Add tests for `sfdp_parse_sector_map_table()` which currently (at the time of this commit) supports flash devices with * no Sector Map Parameter Table (i.e. the whole flash is uniform and non-configurable) * a single descriptor in the Sector Map Parameter Table (i.e. the flash layout is non-configurable and has multiple regions) Support and unit tests for flashes with multiple configurable layouts will be added in the future. Note: The implementation of `sfdp_parse_sector_map_table()` assumes the table to be valid if read succeeds, so the SFDP reader callback needs to ensure it reads data correctly or return an error.
1 parent f08c3cd commit ab46817

File tree

1 file changed

+207
-0
lines changed

1 file changed

+207
-0
lines changed

storage/blockdevice/tests/UNITTESTS/SFDP/test_sfdp.cpp

+207
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,126 @@
1818
#include "gmock/gmock.h"
1919
#include "blockdevice/internal/SFDP.h"
2020

21+
using ::testing::_;
22+
using ::testing::MockFunction;
23+
using ::testing::Return;
24+
25+
/**
26+
* The Sector Map Parameter Table of Cypress S25FS512S:
27+
* https://www.cypress.com/file/216376/download Table 71.
28+
*/
29+
static const mbed::bd_addr_t sector_map_start_addr = 0xD81000;
30+
static const uint8_t sector_map_multiple_descriptors[] = {
31+
// Detect 1
32+
0xFC, 0x65, 0xFF, 0x08,
33+
0x04, 0x00, 0x00, 0x00,
34+
35+
// Detect 2
36+
0xFC, 0x65, 0xFF, 0x04,
37+
0x02, 0x00, 0x00, 0x00,
38+
39+
// Detect 3
40+
0xFD, 0x65, 0xFF, 0x02,
41+
0x04, 0x00, 0x00, 0x00,
42+
43+
// Config 1
44+
0xFE, 0x01, 0x02, 0xFF, // header
45+
0xF1, 0x7F, 0x00, 0x00, // region 0
46+
0xF4, 0x7F, 0x03, 0x00, // region 1
47+
0xF4, 0xFF, 0xFB, 0x03, // region 2
48+
49+
// No Config 2
50+
51+
// Config 3
52+
0xFE, 0x03, 0x02, 0xFF, // header
53+
0xF4, 0xFF, 0xFB, 0x03, // region 0
54+
0xF4, 0x7F, 0x03, 0x00, // region 1
55+
0xF1, 0x7F, 0x00, 0x00, // region 2
56+
57+
// Config 4
58+
0xFF, 0x05, 0x00, 0xFF, // header
59+
0xF4, 0xFF, 0xFF, 0x03 // region 0
60+
};
61+
62+
/**
63+
* Modified to have one descriptor, three regions for test purpose.
64+
*/
65+
static const uint8_t sector_map_single_descriptor[] {
66+
0xFF, 0x01, 0x02, 0xFF, // header, highest region = 0x02
67+
0xF1, 0x7F, 0x00, 0x00, // region 0
68+
0xF4, 0x7F, 0x03, 0x00, // region 1
69+
0xF4, 0xFF, 0xFB, 0x03 // region 2
70+
};
71+
72+
/**
73+
* Modified to have one descriptor, twelve regions for test purpose.
74+
*/
75+
static const uint8_t sector_map_single_descriptor_twelve_regions[] {
76+
0xFF, 0x01, 0x0B, 0xFF, // header, highest region = 0x0B
77+
0xF1, 0x7F, 0x00, 0x00, // region 0
78+
0xF4, 0x7F, 0x03, 0x00, // region 1
79+
0xF4, 0xFF, 0xFB, 0x03, // region 2
80+
0xF1, 0x7F, 0x00, 0x00, // region 3
81+
0xF4, 0x7F, 0x03, 0x00, // region 4
82+
0xF4, 0xFF, 0xFB, 0x03, // region 5
83+
0xF1, 0x7F, 0x00, 0x00, // region 6
84+
0xF4, 0x7F, 0x03, 0x00, // region 7
85+
0xF4, 0xFF, 0xFB, 0x03, // region 8
86+
0xF1, 0x7F, 0x00, 0x00, // region 9
87+
0xF4, 0x7F, 0x03, 0x00, // region 10
88+
0xF4, 0xFF, 0xFB, 0x03, // region 11
89+
};
90+
2191
class TestSFDP : public testing::Test {
92+
93+
public:
94+
mbed::Callback<int(mbed::bd_addr_t, void*, bd_size_t)> sfdp_reader_callback;
95+
96+
protected:
97+
TestSFDP() : sfdp_reader_callback(this, &TestSFDP::sfdp_reader) {};
98+
99+
int sfdp_reader(mbed::bd_addr_t addr, void *buff, bd_size_t buff_size)
100+
{
101+
int mock_return = sfdp_reader_mock.Call(addr, buff, buff_size);
102+
if (mock_return != 0) {
103+
return mock_return;
104+
}
105+
106+
memcpy(buff, sector_descriptors, sector_descriptors_size);
107+
return 0;
108+
};
109+
110+
void set_sector_map_param_table(mbed::sfdp_smptbl_info &smptbl, const uint8_t *table, const size_t table_size)
111+
{
112+
smptbl.size = table_size;
113+
smptbl.addr = sector_map_start_addr;
114+
115+
sector_descriptors = table;
116+
sector_descriptors_size = table_size;
117+
}
118+
119+
MockFunction<int(mbed::bd_addr_t, void*, bd_size_t)> sfdp_reader_mock;
120+
const uint8_t *sector_descriptors;
121+
bd_size_t sector_descriptors_size;
22122
};
23123

124+
/**
125+
* Utilities for conversions to bytes.
126+
*/
127+
namespace{
128+
auto operator "" _B(unsigned long long int size) {
129+
return size;
130+
}
131+
132+
auto operator "" _KB(unsigned long long int size) {
133+
return size * 1024;
134+
}
135+
136+
auto operator "" _MB(unsigned long long int size) {
137+
return size * 1024 * 1024;
138+
}
139+
}
140+
24141
/**
25142
* Test if sfdp_iterate_next_largest_erase_type() returns the most
26143
* optimal erase type, whose erase size is as large as possible
@@ -89,3 +206,93 @@ TEST_F(TestSFDP, TestEraseTypeAlgorithm)
89206
smptbl);
90207
EXPECT_EQ(type, -1); // Invalid erase
91208
}
209+
210+
/**
211+
* Test that sfdp_parse_sector_map_table() treats a whole flash
212+
* as one region if no sector map is available.
213+
*/
214+
TEST_F(TestSFDP, TestNoSectorMap)
215+
{
216+
const bd_size_t device_size = 512_KB;
217+
218+
mbed::sfdp_hdr_info header_info;
219+
header_info.smptbl.size = 0; // No Sector Map Table
220+
header_info.bptbl.device_size_bytes = device_size;
221+
222+
// No need to read anything
223+
EXPECT_CALL(sfdp_reader_mock, Call(_, _, _)).Times(0);
224+
225+
EXPECT_EQ(0, sfdp_parse_sector_map_table(sfdp_reader_callback, header_info));
226+
227+
EXPECT_EQ(1, header_info.smptbl.region_cnt);
228+
EXPECT_EQ(device_size, header_info.smptbl.region_size[0]);
229+
EXPECT_EQ(device_size - 1, header_info.smptbl.region_high_boundary[0]);
230+
}
231+
232+
/**
233+
* When a Sector Map Parameter Table has a single descriptor (i.e. non-configurable flash layout).
234+
*/
235+
TEST_F(TestSFDP, TestSingleSectorConfig)
236+
{
237+
mbed::sfdp_hdr_info header_info;
238+
set_sector_map_param_table(header_info.smptbl, sector_map_single_descriptor, sizeof(sector_map_single_descriptor));
239+
240+
EXPECT_CALL(sfdp_reader_mock, Call(sector_map_start_addr, _, sizeof(sector_map_single_descriptor)))
241+
.Times(1)
242+
.WillOnce(Return(0));
243+
244+
EXPECT_EQ(0, sfdp_parse_sector_map_table(sfdp_reader_callback, header_info));
245+
246+
// Three regions
247+
EXPECT_EQ(3, header_info.smptbl.region_cnt);
248+
249+
// Region 0: erase type 1 (32KB erase)
250+
EXPECT_EQ(32_KB, header_info.smptbl.region_size[0]);
251+
EXPECT_EQ(32_KB - 1_B, header_info.smptbl.region_high_boundary[0]);
252+
EXPECT_EQ(1 << (1 - 1), header_info.smptbl.region_erase_types_bitfld[0]);
253+
254+
// Region 1: erase type 3 (256KB erase which includes 32KB from Region 0)
255+
EXPECT_EQ(224_KB, header_info.smptbl.region_size[1]);
256+
EXPECT_EQ(256_KB - 1_B, header_info.smptbl.region_high_boundary[1]);
257+
EXPECT_EQ(1 << (3 - 1), header_info.smptbl.region_erase_types_bitfld[1]);
258+
259+
// Region 2: erase type 3 (256KB erase)
260+
EXPECT_EQ(64_MB - 32_KB - 224_KB, header_info.smptbl.region_size[2]);
261+
EXPECT_EQ(64_MB - 1_B, header_info.smptbl.region_high_boundary[2]);
262+
EXPECT_EQ(1 << (3 - 1), header_info.smptbl.region_erase_types_bitfld[2]);
263+
}
264+
265+
/**
266+
* When an SFDP reader fails to read data requested by sfdp_parse_sector_map_table().
267+
*/
268+
TEST_F(TestSFDP, TestSFDPReadFailure)
269+
{
270+
mbed::sfdp_hdr_info header_info;
271+
set_sector_map_param_table(header_info.smptbl, sector_map_single_descriptor, sizeof(sector_map_single_descriptor));
272+
273+
EXPECT_CALL(sfdp_reader_mock, Call(sector_map_start_addr, _, sizeof(sector_map_single_descriptor)))
274+
.Times(1)
275+
.WillOnce(Return(-1)); // Emulate read failure
276+
277+
EXPECT_EQ(-1, sfdp_parse_sector_map_table(sfdp_reader_callback, header_info));
278+
}
279+
280+
/**
281+
* When a flash layout has more regions than Mbed OS supports (10).
282+
* Note: This is unlikely to happens in practice.
283+
*/
284+
TEST_F(TestSFDP, TestMoreRegionsThanSupported)
285+
{
286+
mbed::sfdp_hdr_info header_info;
287+
set_sector_map_param_table(
288+
header_info.smptbl,
289+
sector_map_single_descriptor_twelve_regions,
290+
sizeof(sector_map_single_descriptor_twelve_regions)
291+
);
292+
293+
EXPECT_CALL(sfdp_reader_mock, Call(sector_map_start_addr, _, sizeof(sector_map_single_descriptor_twelve_regions)))
294+
.Times(1)
295+
.WillOnce(Return(0));
296+
297+
EXPECT_EQ(-1, sfdp_parse_sector_map_table(sfdp_reader_callback, header_info));
298+
}

0 commit comments

Comments
 (0)