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