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 #ifndef FLASH_HPP_
30 #define FLASH_HPP_
31 
32 #include "openthread-core-config.h"
33 
34 #if OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
35 
36 #include <stdint.h>
37 #include <string.h>
38 
39 #include <openthread/platform/toolchain.h>
40 
41 #include "common/debug.hpp"
42 #include "common/error.hpp"
43 #include "common/locator.hpp"
44 
45 namespace ot {
46 
47 /**
48  * This class implements the flash storage driver.
49  *
50  */
51 class Flash : public InstanceLocator
52 {
53 public:
54     /**
55      * Constructor.
56      *
57      */
Flash(Instance & aInstance)58     explicit Flash(Instance &aInstance)
59         : InstanceLocator(aInstance)
60     {
61     }
62 
63     /**
64      * This method initializes the flash storage driver.
65      *
66      */
67     void Init(void);
68 
69     /**
70      * This method fetches the value identified by @p aKey.
71      *
72      * @param[in]      aKey          The key associated with the requested value.
73      * @param[in]      aIndex        The index of the specific item to get.
74      * @param[out]     aValue        A pointer to where the value of the setting should be written.
75      *                               May be `nullptr` if just testing for the presence or length of a key.
76      * @param[in,out]  aValueLength  A pointer to the length of the value.
77      *                               When called, this should point to an integer containing the maximum bytes that
78      *                               can be written to @p aValue.
79      *                               At return, the actual length of the setting is written.
80      *                               May be `nullptr` if performing a presence check.
81      *
82      * @retval kErrorNone       The value was fetched successfully.
83      * @retval kErrorNotFound   The key was not found.
84      *
85      */
86     Error Get(uint16_t aKey, int aIndex, uint8_t *aValue, uint16_t *aValueLength) const;
87 
88     /**
89      * This method sets or replaces the value identified by @p aKey.
90      *
91      * If there was more than one value previously associated with @p aKey, then they are all deleted and replaced with
92      * this single entry.
93      *
94      * @param[in]  aKey          The key associated with the value.
95      * @param[in]  aValue        A pointer to where the new value of the setting should be read from.
96      *                           MUST NOT be `nullptr` if @p aValueLength is non-zero.
97      * @param[in]  aValueLength  The length of the data pointed to by @p aValue. May be zero.
98      *
99      * @retval kErrorNone     The value was changed.
100      * @retval kErrorNoBufs   Not enough space to store the value.
101      *
102      */
103     Error Set(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength);
104 
105     /**
106      * This method adds a value to @p aKey.
107      *
108      * @param[in]  aKey          The key associated with the value.
109      * @param[in]  aValue        A pointer to where the new value of the setting should be read from.
110      *                           MUST NOT be `nullptr` if @p aValueLength is non-zero.
111      * @param[in]  aValueLength  The length of the data pointed to by @p aValue. May be zero.
112      *
113      * @retval kErrorNone    The value was added.
114      * @retval kErrorNoBufs  Not enough space to store the value.
115      *
116      */
117     Error Add(uint16_t aKey, const uint8_t *aValue, uint16_t aValueLength);
118 
119     /**
120      * This method removes a value from @p aKey.
121      *
122      *
123      * @param[in] aKey    The key associated with the value.
124      * @param[in] aIndex  The index of the value to be removed.
125      *                    If set to -1, all values for @p aKey will be removed.
126      *
127      * @retval kErrorNone      The given key and index was found and removed successfully.
128      * @retval kErrorNotFound  The given key or index was not found.
129      *
130      */
131     Error Delete(uint16_t aKey, int aIndex);
132 
133     /**
134      * This method removes all values.
135      *
136      */
137     void Wipe(void);
138 
139 private:
140     static constexpr uint32_t kSwapMarkerSize = 4; // in bytes
141 
142     static const uint32_t sSwapActive   = 0xbe5cc5ee;
143     static const uint32_t sSwapInactive = 0xbe5cc5ec;
144 
145     OT_TOOL_PACKED_BEGIN
146     class RecordHeader
147     {
148     public:
Init(uint16_t aKey,bool aFirst)149         void Init(uint16_t aKey, bool aFirst)
150         {
151             mKey   = aKey;
152             mFlags = kFlagsInit & ~kFlagAddBegin;
153 
154             if (aFirst)
155             {
156                 mFlags &= ~kFlagFirst;
157             }
158 
159             mLength   = 0;
160             mReserved = 0xffff;
161         }
162 
GetKey(void) const163         uint16_t GetKey(void) const { return mKey; }
SetKey(uint16_t aKey)164         void     SetKey(uint16_t aKey) { mKey = aKey; }
165 
GetLength(void) const166         uint16_t GetLength(void) const { return mLength; }
SetLength(uint16_t aLength)167         void     SetLength(uint16_t aLength) { mLength = aLength; }
168 
GetSize(void) const169         uint16_t GetSize(void) const { return sizeof(*this) + ((mLength + 3) & 0xfffc); }
170 
IsValid(void) const171         bool IsValid(void) const { return ((mFlags & (kFlagAddComplete | kFlagDelete)) == kFlagDelete); }
172 
IsAddBeginSet(void) const173         bool IsAddBeginSet(void) const { return (mFlags & kFlagAddBegin) == 0; }
SetAddBeginFlag(void)174         void SetAddBeginFlag(void) { mFlags &= ~kFlagAddBegin; }
175 
IsAddCompleteSet(void) const176         bool IsAddCompleteSet(void) const { return (mFlags & kFlagAddComplete) == 0; }
SetAddCompleteFlag(void)177         void SetAddCompleteFlag(void) { mFlags &= ~kFlagAddComplete; }
178 
IsDeleted(void) const179         bool IsDeleted(void) const { return (mFlags & kFlagDelete) == 0; }
SetDeleted(void)180         void SetDeleted(void) { mFlags &= ~kFlagDelete; }
181 
IsFirst(void) const182         bool IsFirst(void) const { return (mFlags & kFlagFirst) == 0; }
SetFirst(void)183         void SetFirst(void) { mFlags &= ~kFlagFirst; }
184 
185     private:
186         static constexpr uint16_t kFlagsInit       = 0xffff; // Flags initialize to all-ones.
187         static constexpr uint16_t kFlagAddBegin    = 1 << 0; // 0 indicates record write has started, 1 otherwise.
188         static constexpr uint16_t kFlagAddComplete = 1 << 1; // 0 indicates record write has completed, 1 otherwise.
189         static constexpr uint16_t kFlagDelete      = 1 << 2; // 0 indicates record was deleted, 1 otherwise.
190         static constexpr uint16_t kFlagFirst       = 1 << 3; // 0 indicates first record for key, 1 otherwise.
191 
192         uint16_t mKey;
193         uint16_t mFlags;
194         uint16_t mLength;
195         uint16_t mReserved;
196     } OT_TOOL_PACKED_END;
197 
198     OT_TOOL_PACKED_BEGIN
199     class Record : public RecordHeader
200     {
201     public:
GetData(void) const202         const uint8_t *GetData(void) const { return mData; }
SetData(const uint8_t * aData,uint16_t aDataLength)203         void           SetData(const uint8_t *aData, uint16_t aDataLength)
204         {
205             OT_ASSERT(aDataLength <= kMaxDataSize);
206             memcpy(mData, aData, aDataLength);
207             SetLength(aDataLength);
208         }
209 
210     private:
211         static constexpr uint16_t kMaxDataSize = 255;
212 
213         uint8_t mData[kMaxDataSize];
214     } OT_TOOL_PACKED_END;
215 
216     Error Add(uint16_t aKey, bool aFirst, const uint8_t *aValue, uint16_t aValueLength);
217     bool  DoesValidRecordExist(uint32_t aOffset, uint16_t aKey) const;
218     void  SanitizeFreeSpace(void);
219     void  Swap(void);
220 
221     uint32_t mSwapSize;
222     uint32_t mSwapUsed;
223     uint8_t  mSwapIndex;
224 };
225 
226 } // namespace ot
227 
228 #endif // OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
229 
230 #endif // FLASH_HPP_
231