1 /*             ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
2  *
3  *                 Copyright (c) 2014-2015 Datalight, Inc.
4  *                     All Rights Reserved Worldwide.
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; use version 2 of the License.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
12  *  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 /*  Businesses and individuals that for commercial or other reasons cannot
21  *  comply with the terms of the GPLv2 license may obtain a commercial license
22  *  before incorporating Reliance Edge into proprietary software for
23  *  distribution in any form.  Visit http://www.datalight.com/reliance-edge for
24  *  more information.
25  */
26 
27 /** @file
28  *  @brief Default implementations of memory manipulation functions.
29  *
30  *  These implementations are intended to be small and simple, and thus forego
31  *  all optimizations.  If the C library is available, or if there are better
32  *  third-party implementations available in the system, those can be used
33  *  instead by defining the appropriate macros in redconf.h.
34  *
35  *  These functions are not intended to be completely 100% ANSI C compatible
36  *  implementations, but rather are designed to meet the needs of Reliance Edge.
37  *  The compatibility is close enough that ANSI C compatible implementations
38  *  can be "dropped in" as replacements without difficulty.
39  */
40 #include <redfs.h>
41 
42 
43 #ifndef RedMemCpyUnchecked
44     static void RedMemCpyUnchecked( void * pDest,
45                                     const void * pSrc,
46                                     uint32_t ulLen );
47 #endif
48 #ifndef RedMemMoveUnchecked
49     static void RedMemMoveUnchecked( void * pDest,
50                                      const void * pSrc,
51                                      uint32_t ulLen );
52 #endif
53 #ifndef RedMemSetUnchecked
54     static void RedMemSetUnchecked( void * pDest,
55                                     uint8_t bVal,
56                                     uint32_t ulLen );
57 #endif
58 #ifndef RedMemCmpUnchecked
59     static int32_t RedMemCmpUnchecked( const void * pMem1,
60                                        const void * pMem2,
61                                        uint32_t ulLen );
62 #endif
63 
64 
65 /** @brief Copy memory from one address to another.
66  *
67  *  The source and destination memory buffers should not overlap.  If the
68  *  buffers overlap, use RedMemMove() instead.
69  *
70  *  @param pDest    The destination buffer.
71  *  @param pSrc     The source buffer.
72  *  @param ulLen    The number of bytes to copy.
73  */
RedMemCpy(void * pDest,const void * pSrc,uint32_t ulLen)74 void RedMemCpy( void * pDest,
75                 const void * pSrc,
76                 uint32_t ulLen )
77 {
78     if( ( pDest == NULL ) || ( pSrc == NULL ) )
79     {
80         REDERROR();
81     }
82     else
83     {
84         RedMemCpyUnchecked( pDest, pSrc, ulLen );
85     }
86 }
87 
88 
89 #ifndef RedMemCpyUnchecked
90 
91 /** @brief Copy memory from one address to another.
92  *
93  *  This function should only be called from RedMemCpy().
94  *
95  *  @param pDest    The destination buffer.
96  *  @param pSrc     The source buffer.
97  *  @param ulLen    The number of bytes to copy.
98  */
RedMemCpyUnchecked(void * pDest,const void * pSrc,uint32_t ulLen)99     static void RedMemCpyUnchecked( void * pDest,
100                                     const void * pSrc,
101                                     uint32_t ulLen )
102     {
103         uint8_t * pbDest = CAST_VOID_PTR_TO_UINT8_PTR( pDest );
104         const uint8_t * pbSrc = CAST_VOID_PTR_TO_CONST_UINT8_PTR( pSrc );
105         uint32_t ulIdx;
106 
107         for( ulIdx = 0U; ulIdx < ulLen; ulIdx++ )
108         {
109             pbDest[ ulIdx ] = pbSrc[ ulIdx ];
110         }
111     }
112 #endif /* ifndef RedMemCpyUnchecked */
113 
114 
115 /** @brief Move memory from one address to another.
116  *
117  *  Supports overlapping memory regions.  If memory regions do not overlap, it
118  *  is generally better to use RedMemCpy() instead.
119  *
120  *  @param pDest    The destination buffer.
121  *  @param pSrc     The source buffer.
122  *  @param ulLen    The number of bytes to copy.
123  */
RedMemMove(void * pDest,const void * pSrc,uint32_t ulLen)124 void RedMemMove( void * pDest,
125                  const void * pSrc,
126                  uint32_t ulLen )
127 {
128     if( ( pDest == NULL ) || ( pSrc == NULL ) )
129     {
130         REDERROR();
131     }
132     else
133     {
134         RedMemMoveUnchecked( pDest, pSrc, ulLen );
135     }
136 }
137 
138 
139 #ifndef RedMemMoveUnchecked
140 
141 /** @brief Move memory from one address to another.
142  *
143  *  This function should only be called from RedMemMove().
144  *
145  *  @param pDest    The destination buffer.
146  *  @param pSrc     The source buffer.
147  *  @param ulLen    The number of bytes to copy.
148  */
RedMemMoveUnchecked(void * pDest,const void * pSrc,uint32_t ulLen)149     static void RedMemMoveUnchecked( void * pDest,
150                                      const void * pSrc,
151                                      uint32_t ulLen )
152     {
153         uint8_t * pbDest = CAST_VOID_PTR_TO_UINT8_PTR( pDest );
154         const uint8_t * pbSrc = CAST_VOID_PTR_TO_CONST_UINT8_PTR( pSrc );
155         uint32_t ulIdx;
156 
157         if( MEMMOVE_MUST_COPY_FORWARD( pbDest, pbSrc ) )
158         {
159             /*  If the destination is lower than the source with overlapping memory
160              *  regions, we must copy from start to end in order to copy the memory
161              *  correctly.
162              *
163              *  Don't use RedMemCpy() to do this.  It is possible that RedMemCpy()
164              *  has been replaced (even though this function has not been replaced)
165              *  with an implementation that cannot handle any kind of buffer
166              *  overlap.
167              */
168             for( ulIdx = 0U; ulIdx < ulLen; ulIdx++ )
169             {
170                 pbDest[ ulIdx ] = pbSrc[ ulIdx ];
171             }
172         }
173         else
174         {
175             ulIdx = ulLen;
176 
177             while( ulIdx > 0U )
178             {
179                 ulIdx--;
180                 pbDest[ ulIdx ] = pbSrc[ ulIdx ];
181             }
182         }
183     }
184 #endif /* RedMemMoveUnchecked */
185 
186 
187 /** @brief Initialize a buffer with the specified byte value.
188  *
189  *  @param pDest    The buffer to initialize.
190  *  @param bVal     The byte value with which to initialize @p pDest.
191  *  @param ulLen    The number of bytes to initialize.
192  */
RedMemSet(void * pDest,uint8_t bVal,uint32_t ulLen)193 void RedMemSet( void * pDest,
194                 uint8_t bVal,
195                 uint32_t ulLen )
196 {
197     if( pDest == NULL )
198     {
199         REDERROR();
200     }
201     else
202     {
203         RedMemSetUnchecked( pDest, bVal, ulLen );
204     }
205 }
206 
207 
208 #ifndef RedMemSetUnchecked
209 
210 /** @brief Initialize a buffer with the specified byte value.
211  *
212  *  This function should only be called from RedMemSet().
213  *
214  *  @param pDest    The buffer to initialize.
215  *  @param bVal     The byte value with which to initialize @p pDest.
216  *  @param ulLen    The number of bytes to initialize.
217  */
RedMemSetUnchecked(void * pDest,uint8_t bVal,uint32_t ulLen)218     static void RedMemSetUnchecked( void * pDest,
219                                     uint8_t bVal,
220                                     uint32_t ulLen )
221     {
222         uint8_t * pbDest = CAST_VOID_PTR_TO_UINT8_PTR( pDest );
223         uint32_t ulIdx;
224 
225         for( ulIdx = 0U; ulIdx < ulLen; ulIdx++ )
226         {
227             pbDest[ ulIdx ] = bVal;
228         }
229     }
230 #endif /* ifndef RedMemSetUnchecked */
231 
232 
233 /** @brief Compare the contents of two buffers.
234  *
235  *  @param pMem1    The first buffer to compare.
236  *  @param pMem2    The second buffer to compare.
237  *  @param ulLen    The length to compare.
238  *
239  *  @return Zero if the two buffers are the same, otherwise nonzero.
240  *
241  *  @retval 0   @p pMem1 and @p pMem2 are the same.
242  *  @retval 1   @p pMem1 is greater than @p pMem2, as determined by the
243  *              values of the first differing bytes.
244  *  @retval -1  @p pMem2 is greater than @p pMem1, as determined by the
245  *              values of the first differing bytes.
246  */
RedMemCmp(const void * pMem1,const void * pMem2,uint32_t ulLen)247 int32_t RedMemCmp( const void * pMem1,
248                    const void * pMem2,
249                    uint32_t ulLen )
250 {
251     int32_t lResult;
252 
253     if( ( pMem1 == NULL ) || ( pMem2 == NULL ) )
254     {
255         REDERROR();
256         lResult = 0;
257     }
258     else
259     {
260         lResult = RedMemCmpUnchecked( pMem1, pMem2, ulLen );
261     }
262 
263     return lResult;
264 }
265 
266 
267 #ifndef RedMemCmpUnchecked
268 
269 /** @brief Compare the contents of two buffers.
270  *
271  *  @param pMem1    The first buffer to compare.
272  *  @param pMem2    The second buffer to compare.
273  *  @param ulLen    The length to compare.
274  *
275  *  @return Zero if the two buffers are the same, otherwise nonzero.
276  */
RedMemCmpUnchecked(const void * pMem1,const void * pMem2,uint32_t ulLen)277     static int32_t RedMemCmpUnchecked( const void * pMem1,
278                                        const void * pMem2,
279                                        uint32_t ulLen )
280     {
281         const uint8_t * pbMem1 = CAST_VOID_PTR_TO_CONST_UINT8_PTR( pMem1 );
282         const uint8_t * pbMem2 = CAST_VOID_PTR_TO_CONST_UINT8_PTR( pMem2 );
283         uint32_t ulIdx = 0U;
284         int32_t lResult;
285 
286         while( ( ulIdx < ulLen ) && ( pbMem1[ ulIdx ] == pbMem2[ ulIdx ] ) )
287         {
288             ulIdx++;
289         }
290 
291         if( ulIdx == ulLen )
292         {
293             lResult = 0;
294         }
295         else if( pbMem1[ ulIdx ] > pbMem2[ ulIdx ] )
296         {
297             lResult = 1;
298         }
299         else
300         {
301             lResult = -1;
302         }
303 
304         return lResult;
305     }
306 #endif /* ifndef RedMemCmpUnchecked */
307