Skip to content

Commit 3da94f8

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 20f762b commit 3da94f8

File tree

2 files changed

+225
-0
lines changed

2 files changed

+225
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright (c) 2021 ARM Limited
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
/**
19+
* Utilities for conversions to bytes.
20+
*/
21+
namespace{
22+
auto operator "" _B(unsigned long long int size) {
23+
return size;
24+
}
25+
26+
auto operator "" _KB(unsigned long long int size) {
27+
return size * 1024;
28+
}
29+
30+
auto operator "" _MB(unsigned long long int size) {
31+
return size * 1024 * 1024;
32+
}
33+
}
34+
35+
/**
36+
* The Sector Map Parameter Table of Cypress S25FS512S:
37+
* https://www.cypress.com/file/216376/download Table 71.
38+
*/
39+
static const mbed::bd_addr_t sector_map_start_addr = 0xD81000;
40+
static const uint8_t sector_map_multiple_descriptors[] = {
41+
// Detect 1
42+
0xFC, 0x65, 0xFF, 0x08,
43+
0x04, 0x00, 0x00, 0x00,
44+
45+
// Detect 2
46+
0xFC, 0x65, 0xFF, 0x04,
47+
0x02, 0x00, 0x00, 0x00,
48+
49+
// Detect 3
50+
0xFD, 0x65, 0xFF, 0x02,
51+
0x04, 0x00, 0x00, 0x00,
52+
53+
// Config 1
54+
0xFE, 0x01, 0x02, 0xFF, // header
55+
0xF1, 0x7F, 0x00, 0x00, // region 0
56+
0xF4, 0x7F, 0x03, 0x00, // region 1
57+
0xF4, 0xFF, 0xFB, 0x03, // region 2
58+
59+
// No Config 2
60+
61+
// Config 3
62+
0xFE, 0x03, 0x02, 0xFF, // header
63+
0xF4, 0xFF, 0xFB, 0x03, // region 0
64+
0xF4, 0x7F, 0x03, 0x00, // region 1
65+
0xF1, 0x7F, 0x00, 0x00, // region 2
66+
67+
// Config 4
68+
0xFF, 0x05, 0x00, 0xFF, // header
69+
0xF4, 0xFF, 0xFF, 0x03 // region 0
70+
};
71+
72+
/**
73+
* Modified to have one descriptor, three regions for test purpose.
74+
*/
75+
static const uint8_t sector_map_single_descriptor[] {
76+
0xFF, 0x01, 0x02, 0xFF, // header, highest region = 0x02
77+
0xF1, 0x7F, 0x00, 0x00, // region 0
78+
0xF4, 0x7F, 0x03, 0x00, // region 1
79+
0xF4, 0xFF, 0xFB, 0x03 // region 2
80+
};
81+
82+
/**
83+
* Modified to have one descriptor, twelve regions for test purpose.
84+
*/
85+
static const uint8_t sector_map_single_descriptor_twelve_regions[] {
86+
0xFF, 0x01, 0x0B, 0xFF, // header, highest region = 0x0B
87+
0xF1, 0x7F, 0x00, 0x00, // region 0
88+
0xF4, 0x7F, 0x03, 0x00, // region 1
89+
0xF4, 0xFF, 0xFB, 0x03, // region 2
90+
0xF1, 0x7F, 0x00, 0x00, // region 3
91+
0xF4, 0x7F, 0x03, 0x00, // region 4
92+
0xF4, 0xFF, 0xFB, 0x03, // region 5
93+
0xF1, 0x7F, 0x00, 0x00, // region 6
94+
0xF4, 0x7F, 0x03, 0x00, // region 7
95+
0xF4, 0xFF, 0xFB, 0x03, // region 8
96+
0xF1, 0x7F, 0x00, 0x00, // region 9
97+
0xF4, 0x7F, 0x03, 0x00, // region 10
98+
0xF4, 0xFF, 0xFB, 0x03, // region 11
99+
};
100+

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

+125
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,43 @@
1717
#include "gtest/gtest.h"
1818
#include "gmock/gmock.h"
1919
#include "blockdevice/internal/SFDP.h"
20+
#include "test_data.h"
21+
22+
using ::testing::_;
23+
using ::testing::MockFunction;
24+
using ::testing::Return;
2025

2126
class TestSFDP : public testing::Test {
27+
28+
public:
29+
mbed::Callback<int(mbed::bd_addr_t, void*, bd_size_t)> sfdp_reader_callback;
30+
31+
protected:
32+
TestSFDP() : sfdp_reader_callback(this, &TestSFDP::sfdp_reader) {};
33+
34+
int sfdp_reader(mbed::bd_addr_t addr, void *buff, bd_size_t buff_size)
35+
{
36+
int mock_return = sfdp_reader_mock.Call(addr, buff, buff_size);
37+
if (mock_return != 0) {
38+
return mock_return;
39+
}
40+
41+
memcpy(buff, sector_descriptors, sector_descriptors_size);
42+
return 0;
43+
};
44+
45+
void set_sector_map_param_table(mbed::sfdp_smptbl_info &smptbl, const uint8_t *table, const size_t table_size)
46+
{
47+
smptbl.size = table_size;
48+
smptbl.addr = sector_map_start_addr;
49+
50+
sector_descriptors = table;
51+
sector_descriptors_size = table_size;
52+
}
53+
54+
MockFunction<int(mbed::bd_addr_t, void*, bd_size_t)> sfdp_reader_mock;
55+
const uint8_t *sector_descriptors;
56+
bd_size_t sector_descriptors_size;
2257
};
2358

2459
/**
@@ -89,3 +124,93 @@ TEST_F(TestSFDP, TestEraseTypeAlgorithm)
89124
smptbl);
90125
EXPECT_EQ(type, -1); // Invalid erase
91126
}
127+
128+
/**
129+
* Test that sfdp_parse_sector_map_table() treats a whole flash
130+
* as one region if no sector map is available.
131+
*/
132+
TEST_F(TestSFDP, TestNoSectorMap)
133+
{
134+
const bd_size_t device_size = 512_KB;
135+
136+
mbed::sfdp_hdr_info header_info;
137+
header_info.smptbl.size = 0; // No Sector Map Table
138+
header_info.bptbl.device_size_bytes = device_size;
139+
140+
// No need to read anything
141+
EXPECT_CALL(sfdp_reader_mock, Call(_, _, _)).Times(0);
142+
143+
EXPECT_EQ(0, sfdp_parse_sector_map_table(sfdp_reader_callback, header_info));
144+
145+
EXPECT_EQ(1, header_info.smptbl.region_cnt);
146+
EXPECT_EQ(device_size, header_info.smptbl.region_size[0]);
147+
EXPECT_EQ(device_size - 1, header_info.smptbl.region_high_boundary[0]);
148+
}
149+
150+
/**
151+
* When a Sector Map Parameter Table has a single descriptor (i.e. non-configurable flash layout).
152+
*/
153+
TEST_F(TestSFDP, TestSingleSectorConfig)
154+
{
155+
mbed::sfdp_hdr_info header_info;
156+
set_sector_map_param_table(header_info.smptbl, sector_map_single_descriptor, sizeof(sector_map_single_descriptor));
157+
158+
EXPECT_CALL(sfdp_reader_mock, Call(sector_map_start_addr, _, sizeof(sector_map_single_descriptor)))
159+
.Times(1)
160+
.WillOnce(Return(0));
161+
162+
EXPECT_EQ(0, sfdp_parse_sector_map_table(sfdp_reader_callback, header_info));
163+
164+
// Three regions
165+
EXPECT_EQ(3, header_info.smptbl.region_cnt);
166+
167+
// Region 0: erase type 1 (32KB erase)
168+
EXPECT_EQ(32_KB, header_info.smptbl.region_size[0]);
169+
EXPECT_EQ(32_KB - 1_B, header_info.smptbl.region_high_boundary[0]);
170+
EXPECT_EQ(1 << (1 - 1), header_info.smptbl.region_erase_types_bitfld[0]);
171+
172+
// Region 1: erase type 3 (256KB erase which includes 32KB from Region 0)
173+
EXPECT_EQ(224_KB, header_info.smptbl.region_size[1]);
174+
EXPECT_EQ(256_KB - 1_B, header_info.smptbl.region_high_boundary[1]);
175+
EXPECT_EQ(1 << (3 - 1), header_info.smptbl.region_erase_types_bitfld[1]);
176+
177+
// Region 2: erase type 3 (256KB erase)
178+
EXPECT_EQ(64_MB - 32_KB - 224_KB, header_info.smptbl.region_size[2]);
179+
EXPECT_EQ(64_MB - 1_B, header_info.smptbl.region_high_boundary[2]);
180+
EXPECT_EQ(1 << (3 - 1), header_info.smptbl.region_erase_types_bitfld[2]);
181+
}
182+
183+
/**
184+
* When an SFDP reader fails to read data requested by sfdp_parse_sector_map_table().
185+
*/
186+
TEST_F(TestSFDP, TestSFDPReadFailure)
187+
{
188+
mbed::sfdp_hdr_info header_info;
189+
set_sector_map_param_table(header_info.smptbl, sector_map_single_descriptor, sizeof(sector_map_single_descriptor));
190+
191+
EXPECT_CALL(sfdp_reader_mock, Call(sector_map_start_addr, _, sizeof(sector_map_single_descriptor)))
192+
.Times(1)
193+
.WillOnce(Return(1)); // Emulate read failure
194+
195+
EXPECT_EQ(-1, sfdp_parse_sector_map_table(sfdp_reader_callback, header_info));
196+
}
197+
198+
/**
199+
* When a flash layout has more regions than Mbed OS supports (10).
200+
* Note: This is unlikely to happens in practice.
201+
*/
202+
TEST_F(TestSFDP, TestMoreRegionsThanSupported)
203+
{
204+
mbed::sfdp_hdr_info header_info;
205+
set_sector_map_param_table(
206+
header_info.smptbl,
207+
sector_map_single_descriptor_twelve_regions,
208+
sizeof(sector_map_single_descriptor_twelve_regions)
209+
);
210+
211+
EXPECT_CALL(sfdp_reader_mock, Call(sector_map_start_addr, _, sizeof(sector_map_single_descriptor_twelve_regions)))
212+
.Times(1)
213+
.WillOnce(Return(0));
214+
215+
EXPECT_EQ(-1, sfdp_parse_sector_map_table(sfdp_reader_callback, header_info));
216+
}

0 commit comments

Comments
 (0)