]>
Commit | Line | Data |
---|---|---|
ab93bbe2 FB |
1 | #ifndef BSWAP_H |
2 | #define BSWAP_H | |
3 | ||
6366ca31 PMD |
4 | #undef bswap16 |
5 | #define bswap16(_x) __builtin_bswap16(_x) | |
6 | #undef bswap32 | |
7 | #define bswap32(_x) __builtin_bswap32(_x) | |
8 | #undef bswap64 | |
9 | #define bswap64(_x) __builtin_bswap64(_x) | |
1360677c | 10 | |
14180d62 IW |
11 | static inline uint32_t bswap24(uint32_t x) |
12 | { | |
13 | return (((x & 0x000000ffU) << 16) | | |
14 | ((x & 0x0000ff00U) << 0) | | |
15 | ((x & 0x00ff0000U) >> 16)); | |
16 | } | |
17 | ||
ab93bbe2 FB |
18 | static inline void bswap16s(uint16_t *s) |
19 | { | |
b1032a23 | 20 | *s = __builtin_bswap16(*s); |
ab93bbe2 FB |
21 | } |
22 | ||
14180d62 IW |
23 | static inline void bswap24s(uint32_t *s) |
24 | { | |
25 | *s = bswap24(*s & 0x00ffffffU); | |
26 | } | |
27 | ||
ab93bbe2 FB |
28 | static inline void bswap32s(uint32_t *s) |
29 | { | |
b1032a23 | 30 | *s = __builtin_bswap32(*s); |
ab93bbe2 FB |
31 | } |
32 | ||
33 | static inline void bswap64s(uint64_t *s) | |
34 | { | |
b1032a23 | 35 | *s = __builtin_bswap64(*s); |
ab93bbe2 FB |
36 | } |
37 | ||
e03b5686 | 38 | #if HOST_BIG_ENDIAN |
af8ffdfd | 39 | #define be_bswap(v, size) (v) |
b1032a23 | 40 | #define le_bswap(v, size) glue(__builtin_bswap, size)(v) |
14180d62 | 41 | #define le_bswap24(v) bswap24(v) |
af8ffdfd | 42 | #define be_bswaps(v, size) |
b1032a23 PMD |
43 | #define le_bswaps(p, size) \ |
44 | do { *p = glue(__builtin_bswap, size)(*p); } while (0) | |
af8ffdfd FB |
45 | #else |
46 | #define le_bswap(v, size) (v) | |
14180d62 | 47 | #define le_bswap24(v) (v) |
b1032a23 | 48 | #define be_bswap(v, size) glue(__builtin_bswap, size)(v) |
af8ffdfd | 49 | #define le_bswaps(v, size) |
b1032a23 PMD |
50 | #define be_bswaps(p, size) \ |
51 | do { *p = glue(__builtin_bswap, size)(*p); } while (0) | |
af8ffdfd FB |
52 | #endif |
53 | ||
7d820b76 PM |
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 | ||
af8ffdfd FB |
112 | #define CPU_CONVERT(endian, size, type)\ |
113 | static inline type endian ## size ## _to_cpu(type v)\ | |
114 | {\ | |
a4cbfe24 | 115 | return glue(endian, _bswap)(v, size);\ |
af8ffdfd FB |
116 | }\ |
117 | \ | |
118 | static inline type cpu_to_ ## endian ## size(type v)\ | |
119 | {\ | |
a4cbfe24 | 120 | return glue(endian, _bswap)(v, size);\ |
af8ffdfd FB |
121 | }\ |
122 | \ | |
123 | static inline void endian ## size ## _to_cpus(type *p)\ | |
124 | {\ | |
a4cbfe24 | 125 | glue(endian, _bswaps)(p, size);\ |
af8ffdfd FB |
126 | }\ |
127 | \ | |
128 | static inline void cpu_to_ ## endian ## size ## s(type *p)\ | |
129 | {\ | |
a4cbfe24 | 130 | glue(endian, _bswaps)(p, size);\ |
af8ffdfd FB |
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 | ||
441330f7 | 141 | /* |
845d80a8 | 142 | * Same as cpu_to_le{16,32,64}, except that gcc will figure the result is |
441330f7 GH |
143 | * a compile-time constant if you pass in a constant. So this can be |
144 | * used to initialize static variables. | |
145 | */ | |
e03b5686 | 146 | #if HOST_BIG_ENDIAN |
845d80a8 IW |
147 | # define const_le64(_x) \ |
148 | ((((_x) & 0x00000000000000ffU) << 56) | \ | |
149 | (((_x) & 0x000000000000ff00U) << 40) | \ | |
150 | (((_x) & 0x0000000000ff0000U) << 24) | \ | |
151 | (((_x) & 0x00000000ff000000U) << 8) | \ | |
152 | (((_x) & 0x000000ff00000000U) >> 8) | \ | |
153 | (((_x) & 0x0000ff0000000000U) >> 24) | \ | |
154 | (((_x) & 0x00ff000000000000U) >> 40) | \ | |
155 | (((_x) & 0xff00000000000000U) >> 56)) | |
441330f7 GH |
156 | # define const_le32(_x) \ |
157 | ((((_x) & 0x000000ffU) << 24) | \ | |
158 | (((_x) & 0x0000ff00U) << 8) | \ | |
159 | (((_x) & 0x00ff0000U) >> 8) | \ | |
160 | (((_x) & 0xff000000U) >> 24)) | |
161 | # define const_le16(_x) \ | |
162 | ((((_x) & 0x00ff) << 8) | \ | |
163 | (((_x) & 0xff00) >> 8)) | |
164 | #else | |
845d80a8 | 165 | # define const_le64(_x) (_x) |
441330f7 GH |
166 | # define const_le32(_x) (_x) |
167 | # define const_le16(_x) (_x) | |
168 | #endif | |
169 | ||
cbbab922 PB |
170 | /* unaligned/endian-independent pointer access */ |
171 | ||
172 | /* | |
173 | * the generic syntax is: | |
174 | * | |
acfea137 | 175 | * load: ld{type}{sign}{size}_{endian}_p(ptr) |
cbbab922 | 176 | * |
acfea137 | 177 | * store: st{type}{size}_{endian}_p(ptr, val) |
cbbab922 PB |
178 | * |
179 | * Note there are small differences with the softmmu access API! | |
180 | * | |
181 | * type is: | |
182 | * (empty): integer access | |
183 | * f : float access | |
184 | * | |
185 | * sign is: | |
db5fd8d7 | 186 | * (empty): for 32 or 64 bit sizes (including floats and doubles) |
cbbab922 PB |
187 | * u : unsigned |
188 | * s : signed | |
189 | * | |
190 | * size is: | |
191 | * b: 8 bits | |
192 | * w: 16 bits | |
14180d62 | 193 | * 24: 24 bits |
cbbab922 PB |
194 | * l: 32 bits |
195 | * q: 64 bits | |
196 | * | |
197 | * endian is: | |
1a3de8db | 198 | * he : host endian |
cbbab922 PB |
199 | * be : big endian |
200 | * le : little endian | |
db5fd8d7 | 201 | * te : target endian |
1a3de8db | 202 | * (except for byte accesses, which have no endian infix). |
db5fd8d7 PM |
203 | * |
204 | * The target endian accessors are obviously only available to source | |
205 | * files which are built per-target; they are defined in cpu-all.h. | |
206 | * | |
207 | * In all cases these functions take a host pointer. | |
208 | * For accessors that take a guest address rather than a | |
209 | * host address, see the cpu_{ld,st}_* accessors defined in | |
210 | * cpu_ldst.h. | |
afa4f665 PM |
211 | * |
212 | * For cases where the size to be used is not fixed at compile time, | |
213 | * there are | |
acfea137 | 214 | * stn_{endian}_p(ptr, sz, val) |
afa4f665 PM |
215 | * which stores @val to @ptr as an @endian-order number @sz bytes in size |
216 | * and | |
acfea137 | 217 | * ldn_{endian}_p(ptr, sz) |
afa4f665 PM |
218 | * which loads @sz bytes from @ptr as an unsigned @endian-order number |
219 | * and returns it in a uint64_t. | |
cbbab922 | 220 | */ |
c732a52d | 221 | |
cbbab922 PB |
222 | static inline int ldub_p(const void *ptr) |
223 | { | |
224 | return *(uint8_t *)ptr; | |
225 | } | |
226 | ||
227 | static inline int ldsb_p(const void *ptr) | |
228 | { | |
229 | return *(int8_t *)ptr; | |
230 | } | |
231 | ||
0064aceb | 232 | static inline void stb_p(void *ptr, uint8_t v) |
cbbab922 PB |
233 | { |
234 | *(uint8_t *)ptr = v; | |
235 | } | |
236 | ||
77b17570 PM |
237 | /* |
238 | * Any compiler worth its salt will turn these memcpy into native unaligned | |
239 | * operations. Thus we don't need to play games with packed attributes, or | |
240 | * inline byte-by-byte stores. | |
241 | * Some compilation environments (eg some fortify-source implementations) | |
242 | * may intercept memcpy() in a way that defeats the compiler optimization, | |
243 | * though, so we use __builtin_memcpy() to give ourselves the best chance | |
244 | * of good performance. | |
245 | */ | |
7db2145a | 246 | |
1a3de8db | 247 | static inline int lduw_he_p(const void *ptr) |
7db2145a RH |
248 | { |
249 | uint16_t r; | |
77b17570 | 250 | __builtin_memcpy(&r, ptr, sizeof(r)); |
7db2145a RH |
251 | return r; |
252 | } | |
253 | ||
1a3de8db | 254 | static inline int ldsw_he_p(const void *ptr) |
7db2145a RH |
255 | { |
256 | int16_t r; | |
77b17570 | 257 | __builtin_memcpy(&r, ptr, sizeof(r)); |
7db2145a RH |
258 | return r; |
259 | } | |
260 | ||
1a3de8db | 261 | static inline void stw_he_p(void *ptr, uint16_t v) |
7db2145a | 262 | { |
77b17570 | 263 | __builtin_memcpy(ptr, &v, sizeof(v)); |
7db2145a RH |
264 | } |
265 | ||
14180d62 IW |
266 | static inline void st24_he_p(void *ptr, uint32_t v) |
267 | { | |
268 | __builtin_memcpy(ptr, &v, 3); | |
269 | } | |
270 | ||
1a3de8db | 271 | static inline int ldl_he_p(const void *ptr) |
7db2145a RH |
272 | { |
273 | int32_t r; | |
77b17570 | 274 | __builtin_memcpy(&r, ptr, sizeof(r)); |
7db2145a RH |
275 | return r; |
276 | } | |
277 | ||
1a3de8db | 278 | static inline void stl_he_p(void *ptr, uint32_t v) |
7db2145a | 279 | { |
77b17570 | 280 | __builtin_memcpy(ptr, &v, sizeof(v)); |
7db2145a RH |
281 | } |
282 | ||
1a3de8db | 283 | static inline uint64_t ldq_he_p(const void *ptr) |
7db2145a RH |
284 | { |
285 | uint64_t r; | |
77b17570 | 286 | __builtin_memcpy(&r, ptr, sizeof(r)); |
7db2145a RH |
287 | return r; |
288 | } | |
289 | ||
1a3de8db | 290 | static inline void stq_he_p(void *ptr, uint64_t v) |
7db2145a | 291 | { |
77b17570 | 292 | __builtin_memcpy(ptr, &v, sizeof(v)); |
7db2145a RH |
293 | } |
294 | ||
cbbab922 PB |
295 | static inline int lduw_le_p(const void *ptr) |
296 | { | |
1a3de8db | 297 | return (uint16_t)le_bswap(lduw_he_p(ptr), 16); |
cbbab922 PB |
298 | } |
299 | ||
300 | static inline int ldsw_le_p(const void *ptr) | |
301 | { | |
1a3de8db | 302 | return (int16_t)le_bswap(lduw_he_p(ptr), 16); |
cbbab922 PB |
303 | } |
304 | ||
305 | static inline int ldl_le_p(const void *ptr) | |
306 | { | |
1a3de8db | 307 | return le_bswap(ldl_he_p(ptr), 32); |
cbbab922 PB |
308 | } |
309 | ||
310 | static inline uint64_t ldq_le_p(const void *ptr) | |
311 | { | |
1a3de8db | 312 | return le_bswap(ldq_he_p(ptr), 64); |
cbbab922 PB |
313 | } |
314 | ||
55e7c29e | 315 | static inline void stw_le_p(void *ptr, uint16_t v) |
cbbab922 | 316 | { |
1a3de8db | 317 | stw_he_p(ptr, le_bswap(v, 16)); |
cbbab922 PB |
318 | } |
319 | ||
14180d62 IW |
320 | static inline void st24_le_p(void *ptr, uint32_t v) |
321 | { | |
322 | st24_he_p(ptr, le_bswap24(v)); | |
323 | } | |
324 | ||
55e7c29e | 325 | static inline void stl_le_p(void *ptr, uint32_t v) |
cbbab922 | 326 | { |
1a3de8db | 327 | stl_he_p(ptr, le_bswap(v, 32)); |
cbbab922 PB |
328 | } |
329 | ||
330 | static inline void stq_le_p(void *ptr, uint64_t v) | |
331 | { | |
1a3de8db | 332 | stq_he_p(ptr, le_bswap(v, 64)); |
cbbab922 PB |
333 | } |
334 | ||
cbbab922 PB |
335 | static inline int lduw_be_p(const void *ptr) |
336 | { | |
1a3de8db | 337 | return (uint16_t)be_bswap(lduw_he_p(ptr), 16); |
cbbab922 PB |
338 | } |
339 | ||
340 | static inline int ldsw_be_p(const void *ptr) | |
341 | { | |
1a3de8db | 342 | return (int16_t)be_bswap(lduw_he_p(ptr), 16); |
cbbab922 PB |
343 | } |
344 | ||
345 | static inline int ldl_be_p(const void *ptr) | |
346 | { | |
1a3de8db | 347 | return be_bswap(ldl_he_p(ptr), 32); |
cbbab922 PB |
348 | } |
349 | ||
350 | static inline uint64_t ldq_be_p(const void *ptr) | |
351 | { | |
1a3de8db | 352 | return be_bswap(ldq_he_p(ptr), 64); |
cbbab922 PB |
353 | } |
354 | ||
55e7c29e | 355 | static inline void stw_be_p(void *ptr, uint16_t v) |
cbbab922 | 356 | { |
1a3de8db | 357 | stw_he_p(ptr, be_bswap(v, 16)); |
cbbab922 PB |
358 | } |
359 | ||
55e7c29e | 360 | static inline void stl_be_p(void *ptr, uint32_t v) |
cbbab922 | 361 | { |
1a3de8db | 362 | stl_he_p(ptr, be_bswap(v, 32)); |
cbbab922 PB |
363 | } |
364 | ||
365 | static inline void stq_be_p(void *ptr, uint64_t v) | |
366 | { | |
1a3de8db | 367 | stq_he_p(ptr, be_bswap(v, 64)); |
cbbab922 PB |
368 | } |
369 | ||
c732a52d RH |
370 | static inline unsigned long leul_to_cpu(unsigned long v) |
371 | { | |
a8139632 | 372 | #if HOST_LONG_BITS == 32 |
91107fdf | 373 | return le_bswap(v, 32); |
a8139632 | 374 | #elif HOST_LONG_BITS == 64 |
91107fdf RH |
375 | return le_bswap(v, 64); |
376 | #else | |
377 | # error Unknown sizeof long | |
378 | #endif | |
c732a52d RH |
379 | } |
380 | ||
afa4f665 PM |
381 | /* Store v to p as a sz byte value in host order */ |
382 | #define DO_STN_LDN_P(END) \ | |
383 | static inline void stn_## END ## _p(void *ptr, int sz, uint64_t v) \ | |
384 | { \ | |
385 | switch (sz) { \ | |
386 | case 1: \ | |
387 | stb_p(ptr, v); \ | |
388 | break; \ | |
389 | case 2: \ | |
390 | stw_ ## END ## _p(ptr, v); \ | |
391 | break; \ | |
392 | case 4: \ | |
393 | stl_ ## END ## _p(ptr, v); \ | |
394 | break; \ | |
395 | case 8: \ | |
396 | stq_ ## END ## _p(ptr, v); \ | |
397 | break; \ | |
398 | default: \ | |
399 | g_assert_not_reached(); \ | |
400 | } \ | |
401 | } \ | |
402 | static inline uint64_t ldn_## END ## _p(const void *ptr, int sz) \ | |
403 | { \ | |
404 | switch (sz) { \ | |
405 | case 1: \ | |
406 | return ldub_p(ptr); \ | |
407 | case 2: \ | |
408 | return lduw_ ## END ## _p(ptr); \ | |
409 | case 4: \ | |
410 | return (uint32_t)ldl_ ## END ## _p(ptr); \ | |
411 | case 8: \ | |
412 | return ldq_ ## END ## _p(ptr); \ | |
413 | default: \ | |
414 | g_assert_not_reached(); \ | |
415 | } \ | |
416 | } | |
417 | ||
418 | DO_STN_LDN_P(he) | |
419 | DO_STN_LDN_P(le) | |
420 | DO_STN_LDN_P(be) | |
421 | ||
422 | #undef DO_STN_LDN_P | |
423 | ||
612d590e RH |
424 | #undef le_bswap |
425 | #undef be_bswap | |
426 | #undef le_bswaps | |
427 | #undef be_bswaps | |
cbbab922 | 428 | |
ab93bbe2 | 429 | #endif /* BSWAP_H */ |