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