1- /* Copyright (c) 2020 ARM Limited
1+ /* Copyright (c) 2020-2021 ARM Limited
22 * SPDX-License-Identifier: Apache-2.0
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
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+
31+ /* *
32+ * Based on Cypress S25FS512S, modified to have one descriptor,
33+ * three regions for test purpose.
34+ */
35+ static const uint8_t sector_map_single_descriptor[] {
36+ 0xFF , 0x01 , 0x02 , 0xFF , // header, highest region = 0x02
37+ 0xF1 , 0x7F , 0x00 , 0x00 , // region 0
38+ 0xF4 , 0x7F , 0x03 , 0x00 , // region 1
39+ 0xF4 , 0xFF , 0xFB , 0x03 // region 2
40+ };
41+
42+ /* *
43+ * Based on Cypress S25FS512S, modified to have one descriptor,
44+ * twelve regions for test purpose.
45+ */
46+ static const uint8_t sector_map_single_descriptor_twelve_regions[] {
47+ 0xFF , 0x01 , 0x0B , 0xFF , // header, highest region = 0x0B
48+ 0xF1 , 0x7F , 0x00 , 0x00 , // region 0
49+ 0xF4 , 0x7F , 0x03 , 0x00 , // region 1
50+ 0xF4 , 0xFF , 0xFB , 0x03 , // region 2
51+ 0xF1 , 0x7F , 0x00 , 0x00 , // region 3
52+ 0xF4 , 0x7F , 0x03 , 0x00 , // region 4
53+ 0xF4 , 0xFF , 0xFB , 0x03 , // region 5
54+ 0xF1 , 0x7F , 0x00 , 0x00 , // region 6
55+ 0xF4 , 0x7F , 0x03 , 0x00 , // region 7
56+ 0xF4 , 0xFF , 0xFB , 0x03 , // region 8
57+ 0xF1 , 0x7F , 0x00 , 0x00 , // region 9
58+ 0xF4 , 0x7F , 0x03 , 0x00 , // region 10
59+ 0xF4 , 0xFF , 0xFB , 0x03 , // region 11
60+ };
61+
2162class TestSFDP : public testing ::Test {
63+
64+ public:
65+ mbed::Callback<int (mbed::bd_addr_t , void *, bd_size_t )> sfdp_reader_callback;
66+
2267protected:
23- struct mbed ::sfdp_smptbl_info smptbl;
68+ TestSFDP () : sfdp_reader_callback(this , &TestSFDP::sfdp_reader) {};
69+
70+ int sfdp_reader (mbed::bd_addr_t addr, void *buff, bd_size_t buff_size)
71+ {
72+ int mock_return = sfdp_reader_mock.Call (addr, buff, buff_size);
73+ if (mock_return != 0 ) {
74+ return mock_return;
75+ }
2476
25- /* *
26- * Construct Mbed OS SFDP info.
27- * Normally this is parsed from the flash-chips's
28- * raw SFDP table bytes, but for unit test we construct
29- * SFDP info manually
30- */
31- virtual void SetUp ()
77+ memcpy (buff, sector_descriptors, sector_descriptors_size);
78+ return 0 ;
79+ };
80+
81+ void set_sector_map_param_table (mbed::sfdp_smptbl_info &smptbl, const uint8_t *table, const size_t table_size)
3282 {
33- // The mock flash supports 4KB, 32KB and 64KB erase types
34- smptbl.erase_type_size_arr [0 ] = 4 * 1024 ;
35- smptbl.erase_type_size_arr [1 ] = 32 * 1024 ;
36- smptbl.erase_type_size_arr [2 ] = 64 * 1024 ;
37-
38- // The mock flash has three regions, with address ranges:
39- // * 0 to 64KB - 1B
40- // * 64KB to 256KB - 1B
41- // * 256KB to 1024KB - 1B
42- smptbl.region_high_boundary [0 ] = 64 * 1024 - 1 ;
43- smptbl.region_high_boundary [1 ] = 256 * 1024 - 1 ;
44- smptbl.region_high_boundary [2 ] = 1024 * 1024 - 1 ;
45-
46- // Bitfields indicating which regions support which erase types
47- smptbl.region_erase_types_bitfld [0 ] = 0b0001 ; // 4KB only
48- smptbl.region_erase_types_bitfld [1 ] = 0b0111 ; // 64KB, 32KB, 4KB
49- smptbl.region_erase_types_bitfld [2 ] = 0b0110 ; // 64KB, 32KB
83+ smptbl.size = table_size;
84+ smptbl.addr = sector_map_start_addr;
85+
86+ sector_descriptors = table;
87+ sector_descriptors_size = table_size;
5088 }
89+
90+ MockFunction<int (mbed::bd_addr_t , void *, bd_size_t )> sfdp_reader_mock;
91+ const uint8_t *sector_descriptors;
92+ bd_size_t sector_descriptors_size;
5193};
5294
95+ /* *
96+ * Utilities for conversions to bytes.
97+ */
98+ namespace {
99+ auto operator " " _B(unsigned long long int size) {
100+ return size;
101+ }
102+
103+ auto operator " " _KB(unsigned long long int size) {
104+ return size * 1024 ;
105+ }
106+
107+ auto operator " " _MB(unsigned long long int size) {
108+ return size * 1024 * 1024 ;
109+ }
110+ }
111+
53112/* *
54113 * Test if sfdp_iterate_next_largest_erase_type() returns the most
55114 * optimal erase type, whose erase size is as large as possible
@@ -63,6 +122,25 @@ TEST_F(TestSFDP, TestEraseTypeAlgorithm)
63122 int region = 1 ;
64123 int type;
65124
125+ // The mock flash supports 4KB, 32KB and 64KB erase types
126+ struct mbed ::sfdp_smptbl_info smptbl;
127+ smptbl.erase_type_size_arr [0 ] = 4 * 1024 ;
128+ smptbl.erase_type_size_arr [1 ] = 32 * 1024 ;
129+ smptbl.erase_type_size_arr [2 ] = 64 * 1024 ;
130+
131+ // The mock flash has three regions, with address ranges:
132+ // * 0 to 64KB - 1B
133+ // * 64KB to 256KB - 1B
134+ // * 256KB to 1024KB - 1B
135+ smptbl.region_high_boundary [0 ] = 64 * 1024 - 1 ;
136+ smptbl.region_high_boundary [1 ] = 256 * 1024 - 1 ;
137+ smptbl.region_high_boundary [2 ] = 1024 * 1024 - 1 ;
138+
139+ // Bitfields indicating which regions support which erase types
140+ smptbl.region_erase_types_bitfld [0 ] = 0b0001 ; // 4KB only
141+ smptbl.region_erase_types_bitfld [1 ] = 0b0111 ; // 64KB, 32KB, 4KB
142+ smptbl.region_erase_types_bitfld [2 ] = 0b0110 ; // 64KB, 32KB
143+
66144 // Expected outcome:
67145 // * The starting position 92KB is 4KB-aligned
68146 // * The next position 96KB (92KB + 4KB) is 32KB-aligned
@@ -99,3 +177,93 @@ TEST_F(TestSFDP, TestEraseTypeAlgorithm)
99177 smptbl);
100178 EXPECT_EQ (type, -1 ); // Invalid erase
101179}
180+
181+ /* *
182+ * Test that sfdp_parse_sector_map_table() treats a whole flash
183+ * as one region if no sector map is available.
184+ */
185+ TEST_F (TestSFDP, TestNoSectorMap)
186+ {
187+ const bd_size_t device_size = 512_KB;
188+
189+ mbed::sfdp_hdr_info header_info;
190+ header_info.smptbl .size = 0 ; // No Sector Map Table
191+ header_info.bptbl .device_size_bytes = device_size;
192+
193+ // No need to read anything
194+ EXPECT_CALL (sfdp_reader_mock, Call (_, _, _)).Times (0 );
195+
196+ EXPECT_EQ (0 , sfdp_parse_sector_map_table (sfdp_reader_callback, header_info));
197+
198+ EXPECT_EQ (1 , header_info.smptbl .region_cnt );
199+ EXPECT_EQ (device_size, header_info.smptbl .region_size [0 ]);
200+ EXPECT_EQ (device_size - 1 , header_info.smptbl .region_high_boundary [0 ]);
201+ }
202+
203+ /* *
204+ * When a Sector Map Parameter Table has a single descriptor (i.e. non-configurable flash layout).
205+ */
206+ TEST_F (TestSFDP, TestSingleSectorConfig)
207+ {
208+ mbed::sfdp_hdr_info header_info;
209+ set_sector_map_param_table (header_info.smptbl , sector_map_single_descriptor, sizeof (sector_map_single_descriptor));
210+
211+ EXPECT_CALL (sfdp_reader_mock, Call (sector_map_start_addr, _, sizeof (sector_map_single_descriptor)))
212+ .Times (1 )
213+ .WillOnce (Return (0 ));
214+
215+ EXPECT_EQ (0 , sfdp_parse_sector_map_table (sfdp_reader_callback, header_info));
216+
217+ // Three regions
218+ EXPECT_EQ (3 , header_info.smptbl .region_cnt );
219+
220+ // Region 0: erase type 1 (32KB erase)
221+ EXPECT_EQ (32_KB, header_info.smptbl .region_size [0 ]);
222+ EXPECT_EQ (32_KB - 1_B, header_info.smptbl .region_high_boundary [0 ]);
223+ EXPECT_EQ (1 << (1 - 1 ), header_info.smptbl .region_erase_types_bitfld [0 ]);
224+
225+ // Region 1: erase type 3 (256KB erase which includes 32KB from Region 0)
226+ EXPECT_EQ (224_KB, header_info.smptbl .region_size [1 ]);
227+ EXPECT_EQ (256_KB - 1_B, header_info.smptbl .region_high_boundary [1 ]);
228+ EXPECT_EQ (1 << (3 - 1 ), header_info.smptbl .region_erase_types_bitfld [1 ]);
229+
230+ // Region 2: erase type 3 (256KB erase)
231+ EXPECT_EQ (64_MB - 32_KB - 224_KB, header_info.smptbl .region_size [2 ]);
232+ EXPECT_EQ (64_MB - 1_B, header_info.smptbl .region_high_boundary [2 ]);
233+ EXPECT_EQ (1 << (3 - 1 ), header_info.smptbl .region_erase_types_bitfld [2 ]);
234+ }
235+
236+ /* *
237+ * When an SFDP reader fails to read data requested by sfdp_parse_sector_map_table().
238+ */
239+ TEST_F (TestSFDP, TestSFDPReadFailure)
240+ {
241+ mbed::sfdp_hdr_info header_info;
242+ set_sector_map_param_table (header_info.smptbl , sector_map_single_descriptor, sizeof (sector_map_single_descriptor));
243+
244+ EXPECT_CALL (sfdp_reader_mock, Call (sector_map_start_addr, _, sizeof (sector_map_single_descriptor)))
245+ .Times (1 )
246+ .WillOnce (Return (-1 )); // Emulate read failure
247+
248+ EXPECT_EQ (-1 , sfdp_parse_sector_map_table (sfdp_reader_callback, header_info));
249+ }
250+
251+ /* *
252+ * When a flash layout has more regions than Mbed OS supports (10).
253+ * Note: This is unlikely to happens in practice.
254+ */
255+ TEST_F (TestSFDP, TestMoreRegionsThanSupported)
256+ {
257+ mbed::sfdp_hdr_info header_info;
258+ set_sector_map_param_table (
259+ header_info.smptbl ,
260+ sector_map_single_descriptor_twelve_regions,
261+ sizeof (sector_map_single_descriptor_twelve_regions)
262+ );
263+
264+ EXPECT_CALL (sfdp_reader_mock, Call (sector_map_start_addr, _, sizeof (sector_map_single_descriptor_twelve_regions)))
265+ .Times (1 )
266+ .WillOnce (Return (0 ));
267+
268+ EXPECT_EQ (-1 , sfdp_parse_sector_map_table (sfdp_reader_callback, header_info));
269+ }
0 commit comments