1 /*
2 * Copyright (c) 2020, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "flash.hpp"
30
31 #if OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
32
33 #include <stdio.h>
34
35 #include <openthread/platform/flash.h>
36
37 #include "common/code_utils.hpp"
38 #include "common/instance.hpp"
39
40 namespace ot {
41
42 const uint32_t ot::Flash::sSwapActive;
43 const uint32_t ot::Flash::sSwapInactive;
44
Init(void)45 void Flash::Init(void)
46 {
47 RecordHeader record;
48
49 otPlatFlashInit(&GetInstance());
50
51 mSwapSize = otPlatFlashGetSwapSize(&GetInstance());
52
53 for (mSwapIndex = 0;; mSwapIndex++)
54 {
55 uint32_t swapMarker;
56
57 if (mSwapIndex >= 2)
58 {
59 Wipe();
60 ExitNow();
61 }
62
63 otPlatFlashRead(&GetInstance(), mSwapIndex, 0, &swapMarker, sizeof(swapMarker));
64
65 if (swapMarker == sSwapActive)
66 {
67 break;
68 }
69 }
70
71 for (mSwapUsed = kSwapMarkerSize; mSwapUsed <= mSwapSize - sizeof(record); mSwapUsed += record.GetSize())
72 {
73 otPlatFlashRead(&GetInstance(), mSwapIndex, mSwapUsed, &record, sizeof(record));
74 if (!record.IsAddBeginSet())
75 {
76 break;
77 }
78
79 if (!record.IsAddCompleteSet())
80 {
81 break;
82 }
83 }
84
85 SanitizeFreeSpace();
86
87 exit:
88 return;
89 }
90
SanitizeFreeSpace(void)91 void Flash::SanitizeFreeSpace(void)
92 {
93 uint32_t temp;
94 bool sanitizeNeeded = false;
95
96 if (mSwapUsed & 3)
97 {
98 ExitNow(sanitizeNeeded = true);
99 }
100
101 for (uint32_t offset = mSwapUsed; offset < mSwapSize; offset += sizeof(temp))
102 {
103 otPlatFlashRead(&GetInstance(), mSwapIndex, offset, &temp, sizeof(temp));
104 if (temp != ~0U)
105 {
106 ExitNow(sanitizeNeeded = true);
107 }
108 }
109
110 exit:
111 if (sanitizeNeeded)
112 {
113 Swap();
114 }
115 }
116
Get(uint16_t aKey,int aIndex,uint8_t * aValue,uint16_t * aValueLength) const117 Error Flash::Get(uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength) const
118 {
119 Error error = kErrorNotFound;
120 uint16_t valueLength = 0;
121 int index = 0; // This must be initialized to 0. See [Note] in Delete().
122 uint32_t offset;
123 RecordHeader record;
124
125 for (offset = kSwapMarkerSize; offset < mSwapUsed; offset += record.GetSize())
126 {
127 otPlatFlashRead(&GetInstance(), mSwapIndex, offset, &record, sizeof(record));
128
129 if ((record.GetKey() != aKey) || !record.IsValid())
130 {
131 continue;
132 }
133
134 if (record.IsFirst())
135 {
136 index = 0;
137 }
138
139 if (index == aIndex)
140 {
141 if (aValue && aValueLength)
142 {
143 uint16_t readLength = *aValueLength;
144
145 if (readLength > record.GetLength())
146 {
147 readLength = record.GetLength();
148 }
149
150 otPlatFlashRead(&GetInstance(), mSwapIndex, offset + sizeof(record), aValue, readLength);
151 }
152
153 valueLength = record.GetLength();
154 error = kErrorNone;
155 }
156
157 index++;
158 }
159
160 if (aValueLength)
161 {
162 *aValueLength = valueLength;
163 }
164
165 return error;
166 }
167
Set(uint16_t aKey,const uint8_t * aValue,uint16_t aValueLength)168 Error Flash::Set(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
169 {
170 return Add(aKey, true, aValue, aValueLength);
171 }
172
Add(uint16_t aKey,const uint8_t * aValue,uint16_t aValueLength)173 Error Flash::Add(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
174 {
175 bool first = (Get(aKey, 0, nullptr, nullptr) == kErrorNotFound);
176
177 return Add(aKey, first, aValue, aValueLength);
178 }
179
Add(uint16_t aKey,bool aFirst,const uint8_t * aValue,uint16_t aValueLength)180 Error Flash::Add(uint16_t aKey, bool aFirst, const uint8_t *aValue, uint16_t aValueLength)
181 {
182 Error error = kErrorNone;
183 Record record;
184
185 record.Init(aKey, aFirst);
186 record.SetData(aValue, aValueLength);
187
188 OT_ASSERT((mSwapSize - record.GetSize()) >= kSwapMarkerSize);
189
190 if ((mSwapSize - record.GetSize()) < mSwapUsed)
191 {
192 Swap();
193 VerifyOrExit((mSwapSize - record.GetSize()) >= mSwapUsed, error = kErrorNoBufs);
194 }
195
196 otPlatFlashWrite(&GetInstance(), mSwapIndex, mSwapUsed, &record, record.GetSize());
197
198 record.SetAddCompleteFlag();
199 otPlatFlashWrite(&GetInstance(), mSwapIndex, mSwapUsed, &record, sizeof(RecordHeader));
200
201 mSwapUsed += record.GetSize();
202
203 exit:
204 return error;
205 }
206
DoesValidRecordExist(uint32_t aOffset,uint16_t aKey) const207 bool Flash::DoesValidRecordExist(uint32_t aOffset, uint16_t aKey) const
208 {
209 RecordHeader record;
210 bool rval = false;
211
212 for (; aOffset < mSwapUsed; aOffset += record.GetSize())
213 {
214 otPlatFlashRead(&GetInstance(), mSwapIndex, aOffset, &record, sizeof(record));
215
216 if (record.IsValid() && record.IsFirst() && (record.GetKey() == aKey))
217 {
218 ExitNow(rval = true);
219 }
220 }
221
222 exit:
223 return rval;
224 }
225
Swap(void)226 void Flash::Swap(void)
227 {
228 uint8_t dstIndex = !mSwapIndex;
229 uint32_t dstOffset = kSwapMarkerSize;
230 Record record;
231
232 otPlatFlashErase(&GetInstance(), dstIndex);
233
234 for (uint32_t srcOffset = kSwapMarkerSize; srcOffset < mSwapUsed; srcOffset += record.GetSize())
235 {
236 otPlatFlashRead(&GetInstance(), mSwapIndex, srcOffset, &record, sizeof(RecordHeader));
237
238 VerifyOrExit(record.IsAddBeginSet());
239
240 if (!record.IsValid() || DoesValidRecordExist(srcOffset + record.GetSize(), record.GetKey()))
241 {
242 continue;
243 }
244
245 otPlatFlashRead(&GetInstance(), mSwapIndex, srcOffset, &record, record.GetSize());
246 otPlatFlashWrite(&GetInstance(), dstIndex, dstOffset, &record, record.GetSize());
247 dstOffset += record.GetSize();
248 }
249
250 exit:
251 otPlatFlashWrite(&GetInstance(), dstIndex, 0, &sSwapActive, sizeof(sSwapActive));
252 otPlatFlashWrite(&GetInstance(), mSwapIndex, 0, &sSwapInactive, sizeof(sSwapInactive));
253
254 mSwapIndex = dstIndex;
255 mSwapUsed = dstOffset;
256 }
257
Delete(uint16_t aKey,int aIndex)258 Error Flash::Delete(uint16_t aKey, int aIndex)
259 {
260 Error error = kErrorNotFound;
261 int index = 0; // This must be initialized to 0. See [Note] below.
262 RecordHeader record;
263
264 for (uint32_t offset = kSwapMarkerSize; offset < mSwapUsed; offset += record.GetSize())
265 {
266 otPlatFlashRead(&GetInstance(), mSwapIndex, offset, &record, sizeof(record));
267
268 if ((record.GetKey() != aKey) || !record.IsValid())
269 {
270 continue;
271 }
272
273 if (record.IsFirst())
274 {
275 index = 0;
276 }
277
278 if ((aIndex == index) || (aIndex == -1))
279 {
280 record.SetDeleted();
281 otPlatFlashWrite(&GetInstance(), mSwapIndex, offset, &record, sizeof(record));
282 error = kErrorNone;
283 }
284
285 /* [Note] If the operation gets interrupted here and aIndex is 0, the next record (index == 1) will never get
286 * marked as first. However, this is not actually an issue because all the methods that iterate over the
287 * settings area initialize the index to 0, without expecting any record to be effectively marked as first. */
288
289 if ((index == 1) && (aIndex == 0))
290 {
291 record.SetFirst();
292 otPlatFlashWrite(&GetInstance(), mSwapIndex, offset, &record, sizeof(record));
293 }
294
295 index++;
296 }
297
298 return error;
299 }
300
Wipe(void)301 void Flash::Wipe(void)
302 {
303 otPlatFlashErase(&GetInstance(), 0);
304 otPlatFlashWrite(&GetInstance(), 0, 0, &sSwapActive, sizeof(sSwapActive));
305
306 mSwapIndex = 0;
307 mSwapUsed = sizeof(sSwapActive);
308 }
309
310 } // namespace ot
311
312 #endif // OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
313