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