1 /** @file
2 * @brief Byte order helpers.
3 */
4
5 /*
6 * Copyright (c) 2015-2016, Intel Corporation.
7 *
8 * SPDX-License-Identifier: Apache-2.0
9 */
10
11 #ifndef ZEPHYR_INCLUDE_SYS_BYTEORDER_H_
12 #define ZEPHYR_INCLUDE_SYS_BYTEORDER_H_
13
14 #include <zephyr/types.h>
15 #include <stddef.h>
16 #include <zephyr/sys/__assert.h>
17 #include <zephyr/toolchain.h>
18
19 /* Internal helpers only used by the sys_* APIs further below */
20 #define __bswap_16(x) ((uint16_t) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)))
21 #define __bswap_24(x) ((uint32_t) ((((x) >> 16) & 0xff) | \
22 (((x)) & 0xff00) | \
23 (((x) & 0xff) << 16)))
24 #define __bswap_32(x) ((uint32_t) ((((x) >> 24) & 0xff) | \
25 (((x) >> 8) & 0xff00) | \
26 (((x) & 0xff00) << 8) | \
27 (((x) & 0xff) << 24)))
28 #define __bswap_48(x) ((uint64_t) ((((x) >> 40) & 0xff) | \
29 (((x) >> 24) & 0xff00) | \
30 (((x) >> 8) & 0xff0000) | \
31 (((x) & 0xff0000) << 8) | \
32 (((x) & 0xff00) << 24) | \
33 (((x) & 0xff) << 40)))
34 #define __bswap_64(x) ((uint64_t) ((((x) >> 56) & 0xff) | \
35 (((x) >> 40) & 0xff00) | \
36 (((x) >> 24) & 0xff0000) | \
37 (((x) >> 8) & 0xff000000) | \
38 (((x) & 0xff000000) << 8) | \
39 (((x) & 0xff0000) << 24) | \
40 (((x) & 0xff00) << 40) | \
41 (((x) & 0xff) << 56)))
42
43 /** @def sys_le16_to_cpu
44 * @brief Convert 16-bit integer from little-endian to host endianness.
45 *
46 * @param val 16-bit integer in little-endian format.
47 *
48 * @return 16-bit integer in host endianness.
49 */
50
51 /** @def sys_cpu_to_le16
52 * @brief Convert 16-bit integer from host endianness to little-endian.
53 *
54 * @param val 16-bit integer in host endianness.
55 *
56 * @return 16-bit integer in little-endian format.
57 */
58
59 /** @def sys_le24_to_cpu
60 * @brief Convert 24-bit integer from little-endian to host endianness.
61 *
62 * @param val 24-bit integer in little-endian format.
63 *
64 * @return 24-bit integer in host endianness.
65 */
66
67 /** @def sys_cpu_to_le24
68 * @brief Convert 24-bit integer from host endianness to little-endian.
69 *
70 * @param val 24-bit integer in host endianness.
71 *
72 * @return 24-bit integer in little-endian format.
73 */
74
75 /** @def sys_le32_to_cpu
76 * @brief Convert 32-bit integer from little-endian to host endianness.
77 *
78 * @param val 32-bit integer in little-endian format.
79 *
80 * @return 32-bit integer in host endianness.
81 */
82
83 /** @def sys_cpu_to_le32
84 * @brief Convert 32-bit integer from host endianness to little-endian.
85 *
86 * @param val 32-bit integer in host endianness.
87 *
88 * @return 32-bit integer in little-endian format.
89 */
90
91 /** @def sys_le48_to_cpu
92 * @brief Convert 48-bit integer from little-endian to host endianness.
93 *
94 * @param val 48-bit integer in little-endian format.
95 *
96 * @return 48-bit integer in host endianness.
97 */
98
99 /** @def sys_cpu_to_le48
100 * @brief Convert 48-bit integer from host endianness to little-endian.
101 *
102 * @param val 48-bit integer in host endianness.
103 *
104 * @return 48-bit integer in little-endian format.
105 */
106
107 /** @def sys_be16_to_cpu
108 * @brief Convert 16-bit integer from big-endian to host endianness.
109 *
110 * @param val 16-bit integer in big-endian format.
111 *
112 * @return 16-bit integer in host endianness.
113 */
114
115 /** @def sys_cpu_to_be16
116 * @brief Convert 16-bit integer from host endianness to big-endian.
117 *
118 * @param val 16-bit integer in host endianness.
119 *
120 * @return 16-bit integer in big-endian format.
121 */
122
123 /** @def sys_be24_to_cpu
124 * @brief Convert 24-bit integer from big-endian to host endianness.
125 *
126 * @param val 24-bit integer in big-endian format.
127 *
128 * @return 24-bit integer in host endianness.
129 */
130
131 /** @def sys_cpu_to_be24
132 * @brief Convert 24-bit integer from host endianness to big-endian.
133 *
134 * @param val 24-bit integer in host endianness.
135 *
136 * @return 24-bit integer in big-endian format.
137 */
138
139 /** @def sys_be32_to_cpu
140 * @brief Convert 32-bit integer from big-endian to host endianness.
141 *
142 * @param val 32-bit integer in big-endian format.
143 *
144 * @return 32-bit integer in host endianness.
145 */
146
147 /** @def sys_cpu_to_be32
148 * @brief Convert 32-bit integer from host endianness to big-endian.
149 *
150 * @param val 32-bit integer in host endianness.
151 *
152 * @return 32-bit integer in big-endian format.
153 */
154
155 /** @def sys_be48_to_cpu
156 * @brief Convert 48-bit integer from big-endian to host endianness.
157 *
158 * @param val 48-bit integer in big-endian format.
159 *
160 * @return 48-bit integer in host endianness.
161 */
162
163 /** @def sys_cpu_to_be48
164 * @brief Convert 48-bit integer from host endianness to big-endian.
165 *
166 * @param val 48-bit integer in host endianness.
167 *
168 * @return 48-bit integer in big-endian format.
169 */
170
171 #ifdef CONFIG_LITTLE_ENDIAN
172 #define sys_le16_to_cpu(val) (val)
173 #define sys_cpu_to_le16(val) (val)
174 #define sys_le24_to_cpu(val) (val)
175 #define sys_cpu_to_le24(val) (val)
176 #define sys_le32_to_cpu(val) (val)
177 #define sys_cpu_to_le32(val) (val)
178 #define sys_le48_to_cpu(val) (val)
179 #define sys_cpu_to_le48(val) (val)
180 #define sys_le64_to_cpu(val) (val)
181 #define sys_cpu_to_le64(val) (val)
182 #define sys_be16_to_cpu(val) __bswap_16(val)
183 #define sys_cpu_to_be16(val) __bswap_16(val)
184 #define sys_be24_to_cpu(val) __bswap_24(val)
185 #define sys_cpu_to_be24(val) __bswap_24(val)
186 #define sys_be32_to_cpu(val) __bswap_32(val)
187 #define sys_cpu_to_be32(val) __bswap_32(val)
188 #define sys_be48_to_cpu(val) __bswap_48(val)
189 #define sys_cpu_to_be48(val) __bswap_48(val)
190 #define sys_be64_to_cpu(val) __bswap_64(val)
191 #define sys_cpu_to_be64(val) __bswap_64(val)
192 #else
193 #define sys_le16_to_cpu(val) __bswap_16(val)
194 #define sys_cpu_to_le16(val) __bswap_16(val)
195 #define sys_le24_to_cpu(val) __bswap_24(val)
196 #define sys_cpu_to_le24(val) __bswap_24(val)
197 #define sys_le32_to_cpu(val) __bswap_32(val)
198 #define sys_cpu_to_le32(val) __bswap_32(val)
199 #define sys_le48_to_cpu(val) __bswap_48(val)
200 #define sys_cpu_to_le48(val) __bswap_48(val)
201 #define sys_le64_to_cpu(val) __bswap_64(val)
202 #define sys_cpu_to_le64(val) __bswap_64(val)
203 #define sys_be16_to_cpu(val) (val)
204 #define sys_cpu_to_be16(val) (val)
205 #define sys_be24_to_cpu(val) (val)
206 #define sys_cpu_to_be24(val) (val)
207 #define sys_be32_to_cpu(val) (val)
208 #define sys_cpu_to_be32(val) (val)
209 #define sys_be48_to_cpu(val) (val)
210 #define sys_cpu_to_be48(val) (val)
211 #define sys_be64_to_cpu(val) (val)
212 #define sys_cpu_to_be64(val) (val)
213 #endif
214
215 /**
216 * @brief Put a 16-bit integer as big-endian to arbitrary location.
217 *
218 * Put a 16-bit integer, originally in host endianness, to a
219 * potentially unaligned memory location in big-endian format.
220 *
221 * @param val 16-bit integer in host endianness.
222 * @param dst Destination memory address to store the result.
223 */
sys_put_be16(uint16_t val,uint8_t dst[2])224 static inline void sys_put_be16(uint16_t val, uint8_t dst[2])
225 {
226 dst[0] = val >> 8;
227 dst[1] = val;
228 }
229
230 /**
231 * @brief Put a 24-bit integer as big-endian to arbitrary location.
232 *
233 * Put a 24-bit integer, originally in host endianness, to a
234 * potentially unaligned memory location in big-endian format.
235 *
236 * @param val 24-bit integer in host endianness.
237 * @param dst Destination memory address to store the result.
238 */
sys_put_be24(uint32_t val,uint8_t dst[3])239 static inline void sys_put_be24(uint32_t val, uint8_t dst[3])
240 {
241 dst[0] = val >> 16;
242 sys_put_be16(val, &dst[1]);
243 }
244
245 /**
246 * @brief Put a 32-bit integer as big-endian to arbitrary location.
247 *
248 * Put a 32-bit integer, originally in host endianness, to a
249 * potentially unaligned memory location in big-endian format.
250 *
251 * @param val 32-bit integer in host endianness.
252 * @param dst Destination memory address to store the result.
253 */
sys_put_be32(uint32_t val,uint8_t dst[4])254 static inline void sys_put_be32(uint32_t val, uint8_t dst[4])
255 {
256 sys_put_be16(val >> 16, dst);
257 sys_put_be16(val, &dst[2]);
258 }
259
260 /**
261 * @brief Put a 48-bit integer as big-endian to arbitrary location.
262 *
263 * Put a 48-bit integer, originally in host endianness, to a
264 * potentially unaligned memory location in big-endian format.
265 *
266 * @param val 48-bit integer in host endianness.
267 * @param dst Destination memory address to store the result.
268 */
sys_put_be48(uint64_t val,uint8_t dst[6])269 static inline void sys_put_be48(uint64_t val, uint8_t dst[6])
270 {
271 sys_put_be16(val >> 32, dst);
272 sys_put_be32(val, &dst[2]);
273 }
274
275 /**
276 * @brief Put a 64-bit integer as big-endian to arbitrary location.
277 *
278 * Put a 64-bit integer, originally in host endianness, to a
279 * potentially unaligned memory location in big-endian format.
280 *
281 * @param val 64-bit integer in host endianness.
282 * @param dst Destination memory address to store the result.
283 */
sys_put_be64(uint64_t val,uint8_t dst[8])284 static inline void sys_put_be64(uint64_t val, uint8_t dst[8])
285 {
286 sys_put_be32(val >> 32, dst);
287 sys_put_be32(val, &dst[4]);
288 }
289
290 /**
291 * @brief Put a 16-bit integer as little-endian to arbitrary location.
292 *
293 * Put a 16-bit integer, originally in host endianness, to a
294 * potentially unaligned memory location in little-endian format.
295 *
296 * @param val 16-bit integer in host endianness.
297 * @param dst Destination memory address to store the result.
298 */
sys_put_le16(uint16_t val,uint8_t dst[2])299 static inline void sys_put_le16(uint16_t val, uint8_t dst[2])
300 {
301 dst[0] = val;
302 dst[1] = val >> 8;
303 }
304
305 /**
306 * @brief Put a 24-bit integer as little-endian to arbitrary location.
307 *
308 * Put a 24-bit integer, originally in host endianness, to a
309 * potentially unaligned memory location in little-endian format.
310 *
311 * @param val 24-bit integer in host endianness.
312 * @param dst Destination memory address to store the result.
313 */
sys_put_le24(uint32_t val,uint8_t dst[3])314 static inline void sys_put_le24(uint32_t val, uint8_t dst[3])
315 {
316 sys_put_le16(val, dst);
317 dst[2] = val >> 16;
318 }
319
320 /**
321 * @brief Put a 32-bit integer as little-endian to arbitrary location.
322 *
323 * Put a 32-bit integer, originally in host endianness, to a
324 * potentially unaligned memory location in little-endian format.
325 *
326 * @param val 32-bit integer in host endianness.
327 * @param dst Destination memory address to store the result.
328 */
sys_put_le32(uint32_t val,uint8_t dst[4])329 static inline void sys_put_le32(uint32_t val, uint8_t dst[4])
330 {
331 sys_put_le16(val, dst);
332 sys_put_le16(val >> 16, &dst[2]);
333 }
334
335 /**
336 * @brief Put a 48-bit integer as little-endian to arbitrary location.
337 *
338 * Put a 48-bit integer, originally in host endianness, to a
339 * potentially unaligned memory location in little-endian format.
340 *
341 * @param val 48-bit integer in host endianness.
342 * @param dst Destination memory address to store the result.
343 */
sys_put_le48(uint64_t val,uint8_t dst[6])344 static inline void sys_put_le48(uint64_t val, uint8_t dst[6])
345 {
346 sys_put_le32(val, dst);
347 sys_put_le16(val >> 32, &dst[4]);
348 }
349
350 /**
351 * @brief Put a 64-bit integer as little-endian to arbitrary location.
352 *
353 * Put a 64-bit integer, originally in host endianness, to a
354 * potentially unaligned memory location in little-endian format.
355 *
356 * @param val 64-bit integer in host endianness.
357 * @param dst Destination memory address to store the result.
358 */
sys_put_le64(uint64_t val,uint8_t dst[8])359 static inline void sys_put_le64(uint64_t val, uint8_t dst[8])
360 {
361 sys_put_le32(val, dst);
362 sys_put_le32(val >> 32, &dst[4]);
363 }
364
365 /**
366 * @brief Get a 16-bit integer stored in big-endian format.
367 *
368 * Get a 16-bit integer, stored in big-endian format in a potentially
369 * unaligned memory location, and convert it to the host endianness.
370 *
371 * @param src Location of the big-endian 16-bit integer to get.
372 *
373 * @return 16-bit integer in host endianness.
374 */
sys_get_be16(const uint8_t src[2])375 static inline uint16_t sys_get_be16(const uint8_t src[2])
376 {
377 return ((uint16_t)src[0] << 8) | src[1];
378 }
379
380 /**
381 * @brief Get a 24-bit integer stored in big-endian format.
382 *
383 * Get a 24-bit integer, stored in big-endian format in a potentially
384 * unaligned memory location, and convert it to the host endianness.
385 *
386 * @param src Location of the big-endian 24-bit integer to get.
387 *
388 * @return 24-bit integer in host endianness.
389 */
sys_get_be24(const uint8_t src[3])390 static inline uint32_t sys_get_be24(const uint8_t src[3])
391 {
392 return ((uint32_t)src[0] << 16) | sys_get_be16(&src[1]);
393 }
394
395 /**
396 * @brief Get a 32-bit integer stored in big-endian format.
397 *
398 * Get a 32-bit integer, stored in big-endian format in a potentially
399 * unaligned memory location, and convert it to the host endianness.
400 *
401 * @param src Location of the big-endian 32-bit integer to get.
402 *
403 * @return 32-bit integer in host endianness.
404 */
sys_get_be32(const uint8_t src[4])405 static inline uint32_t sys_get_be32(const uint8_t src[4])
406 {
407 return ((uint32_t)sys_get_be16(&src[0]) << 16) | sys_get_be16(&src[2]);
408 }
409
410 /**
411 * @brief Get a 48-bit integer stored in big-endian format.
412 *
413 * Get a 48-bit integer, stored in big-endian format in a potentially
414 * unaligned memory location, and convert it to the host endianness.
415 *
416 * @param src Location of the big-endian 48-bit integer to get.
417 *
418 * @return 48-bit integer in host endianness.
419 */
sys_get_be48(const uint8_t src[6])420 static inline uint64_t sys_get_be48(const uint8_t src[6])
421 {
422 return ((uint64_t)sys_get_be32(&src[0]) << 16) | sys_get_be16(&src[4]);
423 }
424
425 /**
426 * @brief Get a 64-bit integer stored in big-endian format.
427 *
428 * Get a 64-bit integer, stored in big-endian format in a potentially
429 * unaligned memory location, and convert it to the host endianness.
430 *
431 * @param src Location of the big-endian 64-bit integer to get.
432 *
433 * @return 64-bit integer in host endianness.
434 */
sys_get_be64(const uint8_t src[8])435 static inline uint64_t sys_get_be64(const uint8_t src[8])
436 {
437 return ((uint64_t)sys_get_be32(&src[0]) << 32) | sys_get_be32(&src[4]);
438 }
439
440 /**
441 * @brief Get a 16-bit integer stored in little-endian format.
442 *
443 * Get a 16-bit integer, stored in little-endian format in a potentially
444 * unaligned memory location, and convert it to the host endianness.
445 *
446 * @param src Location of the little-endian 16-bit integer to get.
447 *
448 * @return 16-bit integer in host endianness.
449 */
sys_get_le16(const uint8_t src[2])450 static inline uint16_t sys_get_le16(const uint8_t src[2])
451 {
452 return ((uint16_t)src[1] << 8) | src[0];
453 }
454
455 /**
456 * @brief Get a 24-bit integer stored in little-endian format.
457 *
458 * Get a 24-bit integer, stored in little-endian format in a potentially
459 * unaligned memory location, and convert it to the host endianness.
460 *
461 * @param src Location of the little-endian 24-bit integer to get.
462 *
463 * @return 24-bit integer in host endianness.
464 */
sys_get_le24(const uint8_t src[3])465 static inline uint32_t sys_get_le24(const uint8_t src[3])
466 {
467 return ((uint32_t)src[2] << 16) | sys_get_le16(&src[0]);
468 }
469
470 /**
471 * @brief Get a 32-bit integer stored in little-endian format.
472 *
473 * Get a 32-bit integer, stored in little-endian format in a potentially
474 * unaligned memory location, and convert it to the host endianness.
475 *
476 * @param src Location of the little-endian 32-bit integer to get.
477 *
478 * @return 32-bit integer in host endianness.
479 */
sys_get_le32(const uint8_t src[4])480 static inline uint32_t sys_get_le32(const uint8_t src[4])
481 {
482 return ((uint32_t)sys_get_le16(&src[2]) << 16) | sys_get_le16(&src[0]);
483 }
484
485 /**
486 * @brief Get a 48-bit integer stored in little-endian format.
487 *
488 * Get a 48-bit integer, stored in little-endian format in a potentially
489 * unaligned memory location, and convert it to the host endianness.
490 *
491 * @param src Location of the little-endian 48-bit integer to get.
492 *
493 * @return 48-bit integer in host endianness.
494 */
sys_get_le48(const uint8_t src[6])495 static inline uint64_t sys_get_le48(const uint8_t src[6])
496 {
497 return ((uint64_t)sys_get_le32(&src[2]) << 16) | sys_get_le16(&src[0]);
498 }
499
500 /**
501 * @brief Get a 64-bit integer stored in little-endian format.
502 *
503 * Get a 64-bit integer, stored in little-endian format in a potentially
504 * unaligned memory location, and convert it to the host endianness.
505 *
506 * @param src Location of the little-endian 64-bit integer to get.
507 *
508 * @return 64-bit integer in host endianness.
509 */
sys_get_le64(const uint8_t src[8])510 static inline uint64_t sys_get_le64(const uint8_t src[8])
511 {
512 return ((uint64_t)sys_get_le32(&src[4]) << 32) | sys_get_le32(&src[0]);
513 }
514
515 /**
516 * @brief Swap one buffer content into another
517 *
518 * Copy the content of src buffer into dst buffer in reversed order,
519 * i.e.: src[n] will be put in dst[end-n]
520 * Where n is an index and 'end' the last index in both arrays.
521 * The 2 memory pointers must be pointing to different areas, and have
522 * a minimum size of given length.
523 *
524 * @param dst A valid pointer on a memory area where to copy the data in
525 * @param src A valid pointer on a memory area where to copy the data from
526 * @param length Size of both dst and src memory areas
527 */
sys_memcpy_swap(void * dst,const void * src,size_t length)528 static inline void sys_memcpy_swap(void *dst, const void *src, size_t length)
529 {
530 uint8_t *pdst = (uint8_t *)dst;
531 const uint8_t *psrc = (const uint8_t *)src;
532
533 __ASSERT(((psrc < pdst && (psrc + length) <= pdst) ||
534 (psrc > pdst && (pdst + length) <= psrc)),
535 "Source and destination buffers must not overlap");
536
537 psrc += length - 1;
538
539 for (; length > 0; length--) {
540 *pdst++ = *psrc--;
541 }
542 }
543
544 /**
545 * @brief Swap buffer content
546 *
547 * In-place memory swap, where final content will be reversed.
548 * I.e.: buf[n] will be put in buf[end-n]
549 * Where n is an index and 'end' the last index of buf.
550 *
551 * @param buf A valid pointer on a memory area to swap
552 * @param length Size of buf memory area
553 */
sys_mem_swap(void * buf,size_t length)554 static inline void sys_mem_swap(void *buf, size_t length)
555 {
556 size_t i;
557
558 for (i = 0; i < (length/2); i++) {
559 uint8_t tmp = ((uint8_t *)buf)[i];
560
561 ((uint8_t *)buf)[i] = ((uint8_t *)buf)[length - 1 - i];
562 ((uint8_t *)buf)[length - 1 - i] = tmp;
563 }
564 }
565
566 #endif /* ZEPHYR_INCLUDE_SYS_BYTEORDER_H_ */
567