1
- /* Copyright (c) 2020 ARM Limited
1
+ /* Copyright (c) 2020-2021 ARM Limited
2
2
* SPDX-License-Identifier: Apache-2.0
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
18
18
#include " gmock/gmock.h"
19
19
#include " blockdevice/internal/SFDP.h"
20
20
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
+
21
62
class TestSFDP : public testing ::Test {
63
+
64
+ public:
65
+ mbed::Callback<int (mbed::bd_addr_t , void *, bd_size_t )> sfdp_reader_callback;
66
+
22
67
protected:
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
+ }
24
76
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)
32
82
{
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;
50
88
}
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;
51
93
};
52
94
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
+
53
112
/* *
54
113
* Test if sfdp_iterate_next_largest_erase_type() returns the most
55
114
* optimal erase type, whose erase size is as large as possible
@@ -63,6 +122,25 @@ TEST_F(TestSFDP, TestEraseTypeAlgorithm)
63
122
int region = 1 ;
64
123
int type;
65
124
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
+
66
144
// Expected outcome:
67
145
// * The starting position 92KB is 4KB-aligned
68
146
// * The next position 96KB (92KB + 4KB) is 32KB-aligned
@@ -99,3 +177,93 @@ TEST_F(TestSFDP, TestEraseTypeAlgorithm)
99
177
smptbl);
100
178
EXPECT_EQ (type, -1 ); // Invalid erase
101
179
}
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