1 /*
2 * lfs utility functions
3 *
4 * Copyright (c) 2022, The littlefs authors.
5 * Copyright (c) 2017, Arm Limited. All rights reserved.
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8 #ifndef LFS_UTIL_H
9 #define LFS_UTIL_H
10
11 // Users can override lfs_util.h with their own configuration by defining
12 // LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h).
13 //
14 // If LFS_CONFIG is used, none of the default utils will be emitted and must be
15 // provided by the config file. To start, I would suggest copying lfs_util.h
16 // and modifying as needed.
17 #ifdef LFS_CONFIG
18 #define LFS_STRINGIZE(x) LFS_STRINGIZE2(x)
19 #define LFS_STRINGIZE2(x) #x
20 #include LFS_STRINGIZE(LFS_CONFIG)
21 #else
22
23 // System includes
24 #include <stdint.h>
25 #include <stdbool.h>
26 #include <string.h>
27 #include <inttypes.h>
28
29 #ifndef LFS_NO_MALLOC
30 #include <stdlib.h>
31 #endif
32 #ifndef LFS_NO_ASSERT
33 #include <assert.h>
34 #endif
35 #if !defined(LFS_NO_DEBUG) || \
36 !defined(LFS_NO_WARN) || \
37 !defined(LFS_NO_ERROR) || \
38 defined(LFS_YES_TRACE)
39 #include <stdio.h>
40 #endif
41
42 #ifdef __cplusplus
43 extern "C"
44 {
45 #endif
46
47
48 // Macros, may be replaced by system specific wrappers. Arguments to these
49 // macros must not have side-effects as the macros can be removed for a smaller
50 // code footprint
51
52 // Logging functions
53 #ifndef LFS_TRACE
54 #ifdef LFS_YES_TRACE
55 #define LFS_TRACE_(fmt, ...) \
56 printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
57 #define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "")
58 #else
59 #define LFS_TRACE(...)
60 #endif
61 #endif
62
63 #ifndef LFS_DEBUG
64 #ifndef LFS_NO_DEBUG
65 #define LFS_DEBUG_(fmt, ...) \
66 printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
67 #define LFS_DEBUG(...) LFS_DEBUG_(__VA_ARGS__, "")
68 #else
69 #define LFS_DEBUG(...)
70 #endif
71 #endif
72
73 #ifndef LFS_WARN
74 #ifndef LFS_NO_WARN
75 #define LFS_WARN_(fmt, ...) \
76 printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
77 #define LFS_WARN(...) LFS_WARN_(__VA_ARGS__, "")
78 #else
79 #define LFS_WARN(...)
80 #endif
81 #endif
82
83 #ifndef LFS_ERROR
84 #ifndef LFS_NO_ERROR
85 #define LFS_ERROR_(fmt, ...) \
86 printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
87 #define LFS_ERROR(...) LFS_ERROR_(__VA_ARGS__, "")
88 #else
89 #define LFS_ERROR(...)
90 #endif
91 #endif
92
93 // Runtime assertions
94 #ifndef LFS_ASSERT
95 #ifndef LFS_NO_ASSERT
96 #define LFS_ASSERT(test) assert(test)
97 #else
98 #define LFS_ASSERT(test)
99 #endif
100 #endif
101
102
103 // Builtin functions, these may be replaced by more efficient
104 // toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more
105 // expensive basic C implementation for debugging purposes
106
107 // Min/max functions for unsigned 32-bit numbers
lfs_max(uint32_t a,uint32_t b)108 static inline uint32_t lfs_max(uint32_t a, uint32_t b) {
109 return (a > b) ? a : b;
110 }
111
lfs_min(uint32_t a,uint32_t b)112 static inline uint32_t lfs_min(uint32_t a, uint32_t b) {
113 return (a < b) ? a : b;
114 }
115
116 // Align to nearest multiple of a size
lfs_aligndown(uint32_t a,uint32_t alignment)117 static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) {
118 return a - (a % alignment);
119 }
120
lfs_alignup(uint32_t a,uint32_t alignment)121 static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) {
122 return lfs_aligndown(a + alignment-1, alignment);
123 }
124
125 // Find the smallest power of 2 greater than or equal to a
lfs_npw2(uint32_t a)126 static inline uint32_t lfs_npw2(uint32_t a) {
127 #if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
128 return 32 - __builtin_clz(a-1);
129 #else
130 uint32_t r = 0;
131 uint32_t s;
132 a -= 1;
133 s = (a > 0xffff) << 4; a >>= s; r |= s;
134 s = (a > 0xff ) << 3; a >>= s; r |= s;
135 s = (a > 0xf ) << 2; a >>= s; r |= s;
136 s = (a > 0x3 ) << 1; a >>= s; r |= s;
137 return (r | (a >> 1)) + 1;
138 #endif
139 }
140
141 // Count the number of trailing binary zeros in a
142 // lfs_ctz(0) may be undefined
lfs_ctz(uint32_t a)143 static inline uint32_t lfs_ctz(uint32_t a) {
144 #if !defined(LFS_NO_INTRINSICS) && defined(__GNUC__)
145 return __builtin_ctz(a);
146 #else
147 return lfs_npw2((a & -a) + 1) - 1;
148 #endif
149 }
150
151 // Count the number of binary ones in a
lfs_popc(uint32_t a)152 static inline uint32_t lfs_popc(uint32_t a) {
153 #if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM))
154 return __builtin_popcount(a);
155 #else
156 a = a - ((a >> 1) & 0x55555555);
157 a = (a & 0x33333333) + ((a >> 2) & 0x33333333);
158 return (((a + (a >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24;
159 #endif
160 }
161
162 // Find the sequence comparison of a and b, this is the distance
163 // between a and b ignoring overflow
lfs_scmp(uint32_t a,uint32_t b)164 static inline int lfs_scmp(uint32_t a, uint32_t b) {
165 return (int)(unsigned)(a - b);
166 }
167
168 // Convert between 32-bit little-endian and native order
lfs_fromle32(uint32_t a)169 static inline uint32_t lfs_fromle32(uint32_t a) {
170 #if !defined(LFS_NO_INTRINSICS) && ( \
171 (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \
172 (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \
173 (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
174 return a;
175 #elif !defined(LFS_NO_INTRINSICS) && ( \
176 (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \
177 (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \
178 (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
179 return __builtin_bswap32(a);
180 #else
181 return (((uint8_t*)&a)[0] << 0) |
182 (((uint8_t*)&a)[1] << 8) |
183 (((uint8_t*)&a)[2] << 16) |
184 (((uint8_t*)&a)[3] << 24);
185 #endif
186 }
187
lfs_tole32(uint32_t a)188 static inline uint32_t lfs_tole32(uint32_t a) {
189 return lfs_fromle32(a);
190 }
191
192 // Convert between 32-bit big-endian and native order
lfs_frombe32(uint32_t a)193 static inline uint32_t lfs_frombe32(uint32_t a) {
194 #if !defined(LFS_NO_INTRINSICS) && ( \
195 (defined( BYTE_ORDER ) && defined( ORDER_LITTLE_ENDIAN ) && BYTE_ORDER == ORDER_LITTLE_ENDIAN ) || \
196 (defined(__BYTE_ORDER ) && defined(__ORDER_LITTLE_ENDIAN ) && __BYTE_ORDER == __ORDER_LITTLE_ENDIAN ) || \
197 (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
198 return __builtin_bswap32(a);
199 #elif !defined(LFS_NO_INTRINSICS) && ( \
200 (defined( BYTE_ORDER ) && defined( ORDER_BIG_ENDIAN ) && BYTE_ORDER == ORDER_BIG_ENDIAN ) || \
201 (defined(__BYTE_ORDER ) && defined(__ORDER_BIG_ENDIAN ) && __BYTE_ORDER == __ORDER_BIG_ENDIAN ) || \
202 (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
203 return a;
204 #else
205 return (((uint8_t*)&a)[0] << 24) |
206 (((uint8_t*)&a)[1] << 16) |
207 (((uint8_t*)&a)[2] << 8) |
208 (((uint8_t*)&a)[3] << 0);
209 #endif
210 }
211
lfs_tobe32(uint32_t a)212 static inline uint32_t lfs_tobe32(uint32_t a) {
213 return lfs_frombe32(a);
214 }
215
216 // Calculate CRC-32 with polynomial = 0x04c11db7
217 uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size);
218
219 // Allocate memory, only used if buffers are not provided to littlefs
220 // Note, memory must be 64-bit aligned
lfs_malloc(size_t size)221 static inline void *lfs_malloc(size_t size) {
222 #ifndef LFS_NO_MALLOC
223 return malloc(size);
224 #else
225 (void)size;
226 return NULL;
227 #endif
228 }
229
230 // Deallocate memory, only used if buffers are not provided to littlefs
lfs_free(void * p)231 static inline void lfs_free(void *p) {
232 #ifndef LFS_NO_MALLOC
233 free(p);
234 #else
235 (void)p;
236 #endif
237 }
238
239
240 #ifdef __cplusplus
241 } /* extern "C" */
242 #endif
243
244 #endif
245 #endif
246