1 // SPDX-License-Identifier: GPL-2.0
2 #ifndef UBLK_TGT_ENDIAN_H
3 #define UBLK_TGT_ENDIAN_H
4
5 #include <byteswap.h>
6
7 /* ublksrv target code private header, not for libublksrv user */
8
bswap16(uint16_t x)9 static inline uint16_t bswap16(uint16_t x)
10 {
11 return bswap_16(x);
12 }
bswap32(uint32_t x)13 static inline uint32_t bswap32(uint32_t x)
14 {
15 return bswap_32(x);
16 }
bswap64(uint64_t x)17 static inline uint64_t bswap64(uint64_t x)
18 {
19 return bswap_64(x);
20 }
21
bswap16s(uint16_t * s)22 static inline void bswap16s(uint16_t *s)
23 {
24 *s = bswap16(*s);
25 }
26
bswap32s(uint32_t * s)27 static inline void bswap32s(uint32_t *s)
28 {
29 *s = bswap32(*s);
30 }
31
bswap64s(uint64_t * s)32 static inline void bswap64s(uint64_t *s)
33 {
34 *s = bswap64(*s);
35 }
36
37 #ifndef glue
38 #define xglue(x, y) x ## y
39 #define glue(x, y) xglue(x, y)
40 #endif
41
42 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
43 #define be_bswap(v, size) (v)
44 #define le_bswap(v, size) glue(bswap, size)(v)
45 #define be_bswaps(v, size)
46 #define le_bswaps(p, size) do { *p = glue(bswap, size)(*p); } while(0)
47 #else
48 #define le_bswap(v, size) (v)
49 #define be_bswap(v, size) glue(bswap, size)(v)
50 #define le_bswaps(v, size)
51 #define be_bswaps(p, size) do { *p = glue(bswap, size)(*p); } while(0)
52 #endif
53
54 /**
55 * Endianness conversion functions between host cpu and specified endianness.
56 * (We list the complete set of prototypes produced by the macros below
57 * to assist people who search the headers to find their definitions.)
58 *
59 * uint16_t le16_to_cpu(uint16_t v);
60 * uint32_t le32_to_cpu(uint32_t v);
61 * uint64_t le64_to_cpu(uint64_t v);
62 * uint16_t be16_to_cpu(uint16_t v);
63 * uint32_t be32_to_cpu(uint32_t v);
64 * uint64_t be64_to_cpu(uint64_t v);
65 *
66 * Convert the value @v from the specified format to the native
67 * endianness of the host CPU by byteswapping if necessary, and
68 * return the converted value.
69 *
70 * uint16_t cpu_to_le16(uint16_t v);
71 * uint32_t cpu_to_le32(uint32_t v);
72 * uint64_t cpu_to_le64(uint64_t v);
73 * uint16_t cpu_to_be16(uint16_t v);
74 * uint32_t cpu_to_be32(uint32_t v);
75 * uint64_t cpu_to_be64(uint64_t v);
76 *
77 * Convert the value @v from the native endianness of the host CPU to
78 * the specified format by byteswapping if necessary, and return
79 * the converted value.
80 *
81 * void le16_to_cpus(uint16_t *v);
82 * void le32_to_cpus(uint32_t *v);
83 * void le64_to_cpus(uint64_t *v);
84 * void be16_to_cpus(uint16_t *v);
85 * void be32_to_cpus(uint32_t *v);
86 * void be64_to_cpus(uint64_t *v);
87 *
88 * Do an in-place conversion of the value pointed to by @v from the
89 * specified format to the native endianness of the host CPU.
90 *
91 * void cpu_to_le16s(uint16_t *v);
92 * void cpu_to_le32s(uint32_t *v);
93 * void cpu_to_le64s(uint64_t *v);
94 * void cpu_to_be16s(uint16_t *v);
95 * void cpu_to_be32s(uint32_t *v);
96 * void cpu_to_be64s(uint64_t *v);
97 *
98 * Do an in-place conversion of the value pointed to by @v from the
99 * native endianness of the host CPU to the specified format.
100 *
101 * Both X_to_cpu() and cpu_to_X() perform the same operation; you
102 * should use whichever one is better documenting of the function your
103 * code is performing.
104 *
105 * Do not use these functions for conversion of values which are in guest
106 * memory, since the data may not be sufficiently aligned for the host CPU's
107 * load and store instructions. Instead you should use the ld*_p() and
108 * st*_p() functions, which perform loads and stores of data of any
109 * required size and endianness and handle possible misalignment.
110 */
111
112 #define CPU_CONVERT(endian, size, type)\
113 static inline type endian ## size ## _to_cpu(type v)\
114 {\
115 return glue(endian, _bswap)(v, size);\
116 }\
117 \
118 static inline type cpu_to_ ## endian ## size(type v)\
119 {\
120 return glue(endian, _bswap)(v, size);\
121 }\
122 \
123 static inline void endian ## size ## _to_cpus(type *p)\
124 {\
125 glue(endian, _bswaps)(p, size);\
126 }\
127 \
128 static inline void cpu_to_ ## endian ## size ## s(type *p)\
129 {\
130 glue(endian, _bswaps)(p, size);\
131 }
132
133 CPU_CONVERT(be, 16, uint16_t)
134 CPU_CONVERT(be, 32, uint32_t)
135 CPU_CONVERT(be, 64, uint64_t)
136
137 CPU_CONVERT(le, 16, uint16_t)
138 CPU_CONVERT(le, 32, uint32_t)
139 CPU_CONVERT(le, 64, uint64_t)
140
141 #endif
142