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 <sys/__assert.h>
17 #include <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 #if __BYTE_ORDER__ == __ORDER_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 #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
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 #else
214 #error "Unknown byte order"
215 #endif
216
217 /**
218 * @brief Put a 16-bit integer as big-endian to arbitrary location.
219 *
220 * Put a 16-bit integer, originally in host endianness, to a
221 * potentially unaligned memory location in big-endian format.
222 *
223 * @param val 16-bit integer in host endianness.
224 * @param dst Destination memory address to store the result.
225 */
sys_put_be16(uint16_t val,uint8_t dst[2])226 static inline void sys_put_be16(uint16_t val, uint8_t dst[2])
227 {
228 dst[0] = val >> 8;
229 dst[1] = val;
230 }
231
232 /**
233 * @brief Put a 24-bit integer as big-endian to arbitrary location.
234 *
235 * Put a 24-bit integer, originally in host endianness, to a
236 * potentially unaligned memory location in big-endian format.
237 *
238 * @param val 24-bit integer in host endianness.
239 * @param dst Destination memory address to store the result.
240 */
sys_put_be24(uint32_t val,uint8_t dst[3])241 static inline void sys_put_be24(uint32_t val, uint8_t dst[3])
242 {
243 dst[0] = val >> 16;
244 sys_put_be16(val, &dst[1]);
245 }
246
247 /**
248 * @brief Put a 32-bit integer as big-endian to arbitrary location.
249 *
250 * Put a 32-bit integer, originally in host endianness, to a
251 * potentially unaligned memory location in big-endian format.
252 *
253 * @param val 32-bit integer in host endianness.
254 * @param dst Destination memory address to store the result.
255 */
sys_put_be32(uint32_t val,uint8_t dst[4])256 static inline void sys_put_be32(uint32_t val, uint8_t dst[4])
257 {
258 sys_put_be16(val >> 16, dst);
259 sys_put_be16(val, &dst[2]);
260 }
261
262 /**
263 * @brief Put a 48-bit integer as big-endian to arbitrary location.
264 *
265 * Put a 48-bit integer, originally in host endianness, to a
266 * potentially unaligned memory location in big-endian format.
267 *
268 * @param val 48-bit integer in host endianness.
269 * @param dst Destination memory address to store the result.
270 */
sys_put_be48(uint64_t val,uint8_t dst[6])271 static inline void sys_put_be48(uint64_t val, uint8_t dst[6])
272 {
273 sys_put_be16(val >> 32, dst);
274 sys_put_be32(val, &dst[2]);
275 }
276
277 /**
278 * @brief Put a 64-bit integer as big-endian to arbitrary location.
279 *
280 * Put a 64-bit integer, originally in host endianness, to a
281 * potentially unaligned memory location in big-endian format.
282 *
283 * @param val 64-bit integer in host endianness.
284 * @param dst Destination memory address to store the result.
285 */
sys_put_be64(uint64_t val,uint8_t dst[8])286 static inline void sys_put_be64(uint64_t val, uint8_t dst[8])
287 {
288 sys_put_be32(val >> 32, dst);
289 sys_put_be32(val, &dst[4]);
290 }
291
292 /**
293 * @brief Put a 16-bit integer as little-endian to arbitrary location.
294 *
295 * Put a 16-bit integer, originally in host endianness, to a
296 * potentially unaligned memory location in little-endian format.
297 *
298 * @param val 16-bit integer in host endianness.
299 * @param dst Destination memory address to store the result.
300 */
sys_put_le16(uint16_t val,uint8_t dst[2])301 static inline void sys_put_le16(uint16_t val, uint8_t dst[2])
302 {
303 dst[0] = val;
304 dst[1] = val >> 8;
305 }
306
307 /**
308 * @brief Put a 24-bit integer as little-endian to arbitrary location.
309 *
310 * Put a 24-bit integer, originally in host endianness, to a
311 * potentially unaligned memory location in littel-endian format.
312 *
313 * @param val 24-bit integer in host endianness.
314 * @param dst Destination memory address to store the result.
315 */
sys_put_le24(uint32_t val,uint8_t dst[3])316 static inline void sys_put_le24(uint32_t val, uint8_t dst[3])
317 {
318 sys_put_le16(val, dst);
319 dst[2] = val >> 16;
320 }
321
322 /**
323 * @brief Put a 32-bit integer as little-endian to arbitrary location.
324 *
325 * Put a 32-bit integer, originally in host endianness, to a
326 * potentially unaligned memory location in little-endian format.
327 *
328 * @param val 32-bit integer in host endianness.
329 * @param dst Destination memory address to store the result.
330 */
sys_put_le32(uint32_t val,uint8_t dst[4])331 static inline void sys_put_le32(uint32_t val, uint8_t dst[4])
332 {
333 sys_put_le16(val, dst);
334 sys_put_le16(val >> 16, &dst[2]);
335 }
336
337 /**
338 * @brief Put a 48-bit integer as little-endian to arbitrary location.
339 *
340 * Put a 48-bit integer, originally in host endianness, to a
341 * potentially unaligned memory location in little-endian format.
342 *
343 * @param val 48-bit integer in host endianness.
344 * @param dst Destination memory address to store the result.
345 */
sys_put_le48(uint64_t val,uint8_t dst[6])346 static inline void sys_put_le48(uint64_t val, uint8_t dst[6])
347 {
348 sys_put_le32(val, dst);
349 sys_put_le16(val >> 32, &dst[4]);
350 }
351
352 /**
353 * @brief Put a 64-bit integer as little-endian to arbitrary location.
354 *
355 * Put a 64-bit integer, originally in host endianness, to a
356 * potentially unaligned memory location in little-endian format.
357 *
358 * @param val 64-bit integer in host endianness.
359 * @param dst Destination memory address to store the result.
360 */
sys_put_le64(uint64_t val,uint8_t dst[8])361 static inline void sys_put_le64(uint64_t val, uint8_t dst[8])
362 {
363 sys_put_le32(val, dst);
364 sys_put_le32(val >> 32, &dst[4]);
365 }
366
367 /**
368 * @brief Get a 16-bit integer stored in big-endian format.
369 *
370 * Get a 16-bit integer, stored in big-endian format in a potentially
371 * unaligned memory location, and convert it to the host endianness.
372 *
373 * @param src Location of the big-endian 16-bit integer to get.
374 *
375 * @return 16-bit integer in host endianness.
376 */
sys_get_be16(const uint8_t src[2])377 static inline uint16_t sys_get_be16(const uint8_t src[2])
378 {
379 return ((uint16_t)src[0] << 8) | src[1];
380 }
381
382 /**
383 * @brief Get a 24-bit integer stored in big-endian format.
384 *
385 * Get a 24-bit integer, stored in big-endian format in a potentially
386 * unaligned memory location, and convert it to the host endianness.
387 *
388 * @param src Location of the big-endian 24-bit integer to get.
389 *
390 * @return 24-bit integer in host endianness.
391 */
sys_get_be24(const uint8_t src[3])392 static inline uint32_t sys_get_be24(const uint8_t src[3])
393 {
394 return ((uint32_t)src[0] << 16) | sys_get_be16(&src[1]);
395 }
396
397 /**
398 * @brief Get a 32-bit integer stored in big-endian format.
399 *
400 * Get a 32-bit integer, stored in big-endian format in a potentially
401 * unaligned memory location, and convert it to the host endianness.
402 *
403 * @param src Location of the big-endian 32-bit integer to get.
404 *
405 * @return 32-bit integer in host endianness.
406 */
sys_get_be32(const uint8_t src[4])407 static inline uint32_t sys_get_be32(const uint8_t src[4])
408 {
409 return ((uint32_t)sys_get_be16(&src[0]) << 16) | sys_get_be16(&src[2]);
410 }
411
412 /**
413 * @brief Get a 48-bit integer stored in big-endian format.
414 *
415 * Get a 48-bit integer, stored in big-endian format in a potentially
416 * unaligned memory location, and convert it to the host endianness.
417 *
418 * @param src Location of the big-endian 48-bit integer to get.
419 *
420 * @return 48-bit integer in host endianness.
421 */
sys_get_be48(const uint8_t src[6])422 static inline uint64_t sys_get_be48(const uint8_t src[6])
423 {
424 return ((uint64_t)sys_get_be32(&src[0]) << 16) | sys_get_be16(&src[4]);
425 }
426
427 /**
428 * @brief Get a 64-bit integer stored in big-endian format.
429 *
430 * Get a 64-bit integer, stored in big-endian format in a potentially
431 * unaligned memory location, and convert it to the host endianness.
432 *
433 * @param src Location of the big-endian 64-bit integer to get.
434 *
435 * @return 64-bit integer in host endianness.
436 */
sys_get_be64(const uint8_t src[8])437 static inline uint64_t sys_get_be64(const uint8_t src[8])
438 {
439 return ((uint64_t)sys_get_be32(&src[0]) << 32) | sys_get_be32(&src[4]);
440 }
441
442 /**
443 * @brief Get a 16-bit integer stored in little-endian format.
444 *
445 * Get a 16-bit integer, stored in little-endian format in a potentially
446 * unaligned memory location, and convert it to the host endianness.
447 *
448 * @param src Location of the little-endian 16-bit integer to get.
449 *
450 * @return 16-bit integer in host endianness.
451 */
sys_get_le16(const uint8_t src[2])452 static inline uint16_t sys_get_le16(const uint8_t src[2])
453 {
454 return ((uint16_t)src[1] << 8) | src[0];
455 }
456
457 /**
458 * @brief Get a 24-bit integer stored in big-endian format.
459 *
460 * Get a 24-bit integer, stored in big-endian format in a potentially
461 * unaligned memory location, and convert it to the host endianness.
462 *
463 * @param src Location of the big-endian 24-bit integer to get.
464 *
465 * @return 24-bit integer in host endianness.
466 */
sys_get_le24(const uint8_t src[3])467 static inline uint32_t sys_get_le24(const uint8_t src[3])
468 {
469 return ((uint32_t)src[2] << 16) | sys_get_le16(&src[0]);
470 }
471
472 /**
473 * @brief Get a 32-bit integer stored in little-endian format.
474 *
475 * Get a 32-bit integer, stored in little-endian format in a potentially
476 * unaligned memory location, and convert it to the host endianness.
477 *
478 * @param src Location of the little-endian 32-bit integer to get.
479 *
480 * @return 32-bit integer in host endianness.
481 */
sys_get_le32(const uint8_t src[4])482 static inline uint32_t sys_get_le32(const uint8_t src[4])
483 {
484 return ((uint32_t)sys_get_le16(&src[2]) << 16) | sys_get_le16(&src[0]);
485 }
486
487 /**
488 * @brief Get a 48-bit integer stored in little-endian format.
489 *
490 * Get a 48-bit integer, stored in little-endian format in a potentially
491 * unaligned memory location, and convert it to the host endianness.
492 *
493 * @param src Location of the little-endian 48-bit integer to get.
494 *
495 * @return 48-bit integer in host endianness.
496 */
sys_get_le48(const uint8_t src[6])497 static inline uint64_t sys_get_le48(const uint8_t src[6])
498 {
499 return ((uint64_t)sys_get_le32(&src[2]) << 16) | sys_get_le16(&src[0]);
500 }
501
502 /**
503 * @brief Get a 64-bit integer stored in little-endian format.
504 *
505 * Get a 64-bit integer, stored in little-endian format in a potentially
506 * unaligned memory location, and convert it to the host endianness.
507 *
508 * @param src Location of the little-endian 64-bit integer to get.
509 *
510 * @return 64-bit integer in host endianness.
511 */
sys_get_le64(const uint8_t src[8])512 static inline uint64_t sys_get_le64(const uint8_t src[8])
513 {
514 return ((uint64_t)sys_get_le32(&src[4]) << 32) | sys_get_le32(&src[0]);
515 }
516
517 /**
518 * @brief Swap one buffer content into another
519 *
520 * Copy the content of src buffer into dst buffer in reversed order,
521 * i.e.: src[n] will be put in dst[end-n]
522 * Where n is an index and 'end' the last index in both arrays.
523 * The 2 memory pointers must be pointing to different areas, and have
524 * a minimum size of given length.
525 *
526 * @param dst A valid pointer on a memory area where to copy the data in
527 * @param src A valid pointer on a memory area where to copy the data from
528 * @param length Size of both dst and src memory areas
529 */
sys_memcpy_swap(void * dst,const void * src,size_t length)530 static inline void sys_memcpy_swap(void *dst, const void *src, size_t length)
531 {
532 uint8_t *pdst = (uint8_t *)dst;
533 const uint8_t *psrc = (const uint8_t *)src;
534
535 __ASSERT(((psrc < pdst && (psrc + length) <= pdst) ||
536 (psrc > pdst && (pdst + length) <= psrc)),
537 "Source and destination buffers must not overlap");
538
539 psrc += length - 1;
540
541 for (; length > 0; length--) {
542 *pdst++ = *psrc--;
543 }
544 }
545
546 /**
547 * @brief Swap buffer content
548 *
549 * In-place memory swap, where final content will be reversed.
550 * I.e.: buf[n] will be put in buf[end-n]
551 * Where n is an index and 'end' the last index of buf.
552 *
553 * @param buf A valid pointer on a memory area to swap
554 * @param length Size of buf memory area
555 */
sys_mem_swap(void * buf,size_t length)556 static inline void sys_mem_swap(void *buf, size_t length)
557 {
558 size_t i;
559
560 for (i = 0; i < (length/2); i++) {
561 uint8_t tmp = ((uint8_t *)buf)[i];
562
563 ((uint8_t *)buf)[i] = ((uint8_t *)buf)[length - 1 - i];
564 ((uint8_t *)buf)[length - 1 - i] = tmp;
565 }
566 }
567
568 #endif /* ZEPHYR_INCLUDE_SYS_BYTEORDER_H_ */
569