• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <openthread/platform/flash.h>
34 
35 #include "instance/instance.hpp"
36 
37 namespace ot {
38 
39 const uint32_t ot::Flash::sSwapActive;
40 const uint32_t ot::Flash::sSwapInactive;
41 
Init(void)42 void Flash::Init(void)
43 {
44     RecordHeader record;
45 
46     otPlatFlashInit(&GetInstance());
47 
48     mSwapSize = otPlatFlashGetSwapSize(&GetInstance());
49 
50     for (mSwapIndex = 0;; mSwapIndex++)
51     {
52         uint32_t swapMarker;
53 
54         if (mSwapIndex >= 2)
55         {
56             Wipe();
57             ExitNow();
58         }
59 
60         otPlatFlashRead(&GetInstance(), mSwapIndex, 0, &swapMarker, sizeof(swapMarker));
61 
62         if (swapMarker == sSwapActive)
63         {
64             break;
65         }
66     }
67 
68     for (mSwapUsed = kSwapMarkerSize; mSwapUsed <= mSwapSize - sizeof(record); mSwapUsed += record.GetSize())
69     {
70         otPlatFlashRead(&GetInstance(), mSwapIndex, mSwapUsed, &record, sizeof(record));
71         if (!record.IsAddBeginSet())
72         {
73             break;
74         }
75 
76         if (!record.IsAddCompleteSet())
77         {
78             break;
79         }
80     }
81 
82     SanitizeFreeSpace();
83 
84 exit:
85     return;
86 }
87 
SanitizeFreeSpace(void)88 void Flash::SanitizeFreeSpace(void)
89 {
90     uint32_t temp;
91     bool     sanitizeNeeded = false;
92 
93     if (mSwapUsed & 3)
94     {
95         ExitNow(sanitizeNeeded = true);
96     }
97 
98     for (uint32_t offset = mSwapUsed; offset < mSwapSize; offset += sizeof(temp))
99     {
100         otPlatFlashRead(&GetInstance(), mSwapIndex, offset, &temp, sizeof(temp));
101         if (temp != ~0U)
102         {
103             ExitNow(sanitizeNeeded = true);
104         }
105     }
106 
107 exit:
108     if (sanitizeNeeded)
109     {
110         Swap();
111     }
112 }
113 
Get(uint16_t aKey,int aIndex,uint8_t * aValue,uint16_t * aValueLength) const114 Error Flash::Get(uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength) const
115 {
116     Error        error       = kErrorNotFound;
117     uint16_t     valueLength = 0;
118     int          index       = 0; // This must be initialized to 0. See [Note] in Delete().
119     uint32_t     offset;
120     RecordHeader record;
121 
122     for (offset = kSwapMarkerSize; offset < mSwapUsed; offset += record.GetSize())
123     {
124         otPlatFlashRead(&GetInstance(), mSwapIndex, offset, &record, sizeof(record));
125 
126         if ((record.GetKey() != aKey) || !record.IsValid())
127         {
128             continue;
129         }
130 
131         if (record.IsFirst())
132         {
133             index = 0;
134         }
135 
136         if (index == aIndex)
137         {
138             if (aValue && aValueLength)
139             {
140                 uint16_t readLength = *aValueLength;
141 
142                 if (readLength > record.GetLength())
143                 {
144                     readLength = record.GetLength();
145                 }
146 
147                 otPlatFlashRead(&GetInstance(), mSwapIndex, offset + sizeof(record), aValue, readLength);
148             }
149 
150             valueLength = record.GetLength();
151             error       = kErrorNone;
152         }
153 
154         index++;
155     }
156 
157     if (aValueLength)
158     {
159         *aValueLength = valueLength;
160     }
161 
162     return error;
163 }
164 
Set(uint16_t aKey,const uint8_t * aValue,uint16_t aValueLength)165 Error Flash::Set(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
166 {
167     return Add(aKey, true, aValue, aValueLength);
168 }
169 
Add(uint16_t aKey,const uint8_t * aValue,uint16_t aValueLength)170 Error Flash::Add(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength)
171 {
172     bool first = (Get(aKey, 0, nullptr, nullptr) == kErrorNotFound);
173 
174     return Add(aKey, first, aValue, aValueLength);
175 }
176 
Add(uint16_t aKey,bool aFirst,const uint8_t * aValue,uint16_t aValueLength)177 Error Flash::Add(uint16_t aKey, bool aFirst, const uint8_t *aValue, uint16_t aValueLength)
178 {
179     Error  error = kErrorNone;
180     Record record;
181 
182     record.Init(aKey, aFirst);
183     record.SetData(aValue, aValueLength);
184 
185     OT_ASSERT((mSwapSize - record.GetSize()) >= kSwapMarkerSize);
186 
187     if ((mSwapSize - record.GetSize()) < mSwapUsed)
188     {
189         Swap();
190         VerifyOrExit((mSwapSize - record.GetSize()) >= mSwapUsed, error = kErrorNoBufs);
191     }
192 
193     otPlatFlashWrite(&GetInstance(), mSwapIndex, mSwapUsed, &record, record.GetSize());
194 
195     record.SetAddCompleteFlag();
196     otPlatFlashWrite(&GetInstance(), mSwapIndex, mSwapUsed, &record, sizeof(RecordHeader));
197 
198     mSwapUsed += record.GetSize();
199 
200 exit:
201     return error;
202 }
203 
DoesValidRecordExist(uint32_t aOffset,uint16_t aKey) const204 bool Flash::DoesValidRecordExist(uint32_t aOffset, uint16_t aKey) const
205 {
206     RecordHeader record;
207     bool         rval = false;
208 
209     for (; aOffset < mSwapUsed; aOffset += record.GetSize())
210     {
211         otPlatFlashRead(&GetInstance(), mSwapIndex, aOffset, &record, sizeof(record));
212 
213         if (record.IsValid() && record.IsFirst() && (record.GetKey() == aKey))
214         {
215             ExitNow(rval = true);
216         }
217     }
218 
219 exit:
220     return rval;
221 }
222 
Swap(void)223 void Flash::Swap(void)
224 {
225     uint8_t  dstIndex  = !mSwapIndex;
226     uint32_t dstOffset = kSwapMarkerSize;
227     Record   record;
228 
229     otPlatFlashErase(&GetInstance(), dstIndex);
230 
231     for (uint32_t srcOffset = kSwapMarkerSize; srcOffset < mSwapUsed; srcOffset += record.GetSize())
232     {
233         otPlatFlashRead(&GetInstance(), mSwapIndex, srcOffset, &record, sizeof(RecordHeader));
234 
235         VerifyOrExit(record.IsAddBeginSet());
236 
237         if (!record.IsValid() || DoesValidRecordExist(srcOffset + record.GetSize(), record.GetKey()))
238         {
239             continue;
240         }
241 
242         otPlatFlashRead(&GetInstance(), mSwapIndex, srcOffset, &record, record.GetSize());
243         otPlatFlashWrite(&GetInstance(), dstIndex, dstOffset, &record, record.GetSize());
244         dstOffset += record.GetSize();
245     }
246 
247 exit:
248     otPlatFlashWrite(&GetInstance(), dstIndex, 0, &sSwapActive, sizeof(sSwapActive));
249     otPlatFlashWrite(&GetInstance(), mSwapIndex, 0, &sSwapInactive, sizeof(sSwapInactive));
250 
251     mSwapIndex = dstIndex;
252     mSwapUsed  = dstOffset;
253 }
254 
Delete(uint16_t aKey,int aIndex)255 Error Flash::Delete(uint16_t aKey, int aIndex)
256 {
257     Error        error = kErrorNotFound;
258     int          index = 0; // This must be initialized to 0. See [Note] below.
259     RecordHeader record;
260 
261     for (uint32_t offset = kSwapMarkerSize; offset < mSwapUsed; offset += record.GetSize())
262     {
263         otPlatFlashRead(&GetInstance(), mSwapIndex, offset, &record, sizeof(record));
264 
265         if ((record.GetKey() != aKey) || !record.IsValid())
266         {
267             continue;
268         }
269 
270         if (record.IsFirst())
271         {
272             index = 0;
273         }
274 
275         if ((aIndex == index) || (aIndex == -1))
276         {
277             record.SetDeleted();
278             otPlatFlashWrite(&GetInstance(), mSwapIndex, offset, &record, sizeof(record));
279             error = kErrorNone;
280         }
281 
282         /* [Note] If the operation gets interrupted here and aIndex is 0, the next record (index == 1) will never get
283          * marked as first. However, this is not actually an issue because all the methods that iterate over the
284          * settings area initialize the index to 0, without expecting any record to be effectively marked as first. */
285 
286         if ((index == 1) && (aIndex == 0))
287         {
288             record.SetFirst();
289             otPlatFlashWrite(&GetInstance(), mSwapIndex, offset, &record, sizeof(record));
290         }
291 
292         index++;
293     }
294 
295     return error;
296 }
297 
Wipe(void)298 void Flash::Wipe(void)
299 {
300     otPlatFlashErase(&GetInstance(), 0);
301     otPlatFlashWrite(&GetInstance(), 0, 0, &sSwapActive, sizeof(sSwapActive));
302 
303     mSwapIndex = 0;
304     mSwapUsed  = sizeof(sSwapActive);
305 }
306 
307 } // namespace ot
308 
309 #endif // OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
310