]>
Commit | Line | Data |
---|---|---|
ab93bbe2 FB |
1 | #ifndef BSWAP_H |
2 | #define BSWAP_H | |
3 | ||
5735147e | 4 | #ifdef CONFIG_MACHINE_BSWAP_H |
cdfe2851 | 5 | # include <sys/endian.h> |
cdfe2851 | 6 | # include <machine/bswap.h> |
de03c316 AF |
7 | #elif defined(__FreeBSD__) |
8 | # include <sys/endian.h> | |
652a46eb DC |
9 | #elif defined(__HAIKU__) |
10 | # include <endian.h> | |
cdfe2851 RH |
11 | #elif defined(CONFIG_BYTESWAP_H) |
12 | # include <byteswap.h> | |
b30a8c24 PM |
13 | #define BSWAP_FROM_BYTESWAP |
14 | # else | |
15 | #define BSWAP_FROM_FALLBACKS | |
16 | #endif /* ! CONFIG_MACHINE_BSWAP_H */ | |
ab93bbe2 | 17 | |
b30a8c24 PM |
18 | #ifdef __cplusplus |
19 | extern "C" { | |
20 | #endif | |
21 | ||
22 | #include "fpu/softfloat-types.h" | |
23 | ||
24 | #ifdef BSWAP_FROM_BYTESWAP | |
ab93bbe2 FB |
25 | static inline uint16_t bswap16(uint16_t x) |
26 | { | |
27 | return bswap_16(x); | |
28 | } | |
29 | ||
5fafdf24 | 30 | static inline uint32_t bswap32(uint32_t x) |
ab93bbe2 FB |
31 | { |
32 | return bswap_32(x); | |
33 | } | |
34 | ||
5fafdf24 | 35 | static inline uint64_t bswap64(uint64_t x) |
ab93bbe2 FB |
36 | { |
37 | return bswap_64(x); | |
38 | } | |
b30a8c24 PM |
39 | #endif |
40 | ||
41 | #ifdef BSWAP_FROM_FALLBACKS | |
cdfe2851 RH |
42 | static inline uint16_t bswap16(uint16_t x) |
43 | { | |
44 | return (((x & 0x00ff) << 8) | | |
45 | ((x & 0xff00) >> 8)); | |
46 | } | |
ab93bbe2 | 47 | |
cdfe2851 RH |
48 | static inline uint32_t bswap32(uint32_t x) |
49 | { | |
50 | return (((x & 0x000000ffU) << 24) | | |
51 | ((x & 0x0000ff00U) << 8) | | |
52 | ((x & 0x00ff0000U) >> 8) | | |
53 | ((x & 0xff000000U) >> 24)); | |
54 | } | |
55 | ||
56 | static inline uint64_t bswap64(uint64_t x) | |
57 | { | |
58 | return (((x & 0x00000000000000ffULL) << 56) | | |
59 | ((x & 0x000000000000ff00ULL) << 40) | | |
60 | ((x & 0x0000000000ff0000ULL) << 24) | | |
61 | ((x & 0x00000000ff000000ULL) << 8) | | |
62 | ((x & 0x000000ff00000000ULL) >> 8) | | |
63 | ((x & 0x0000ff0000000000ULL) >> 24) | | |
64 | ((x & 0x00ff000000000000ULL) >> 40) | | |
65 | ((x & 0xff00000000000000ULL) >> 56)); | |
66 | } | |
b30a8c24 PM |
67 | #endif |
68 | ||
69 | #undef BSWAP_FROM_BYTESWAP | |
70 | #undef BSWAP_FROM_FALLBACKS | |
1360677c | 71 | |
ab93bbe2 FB |
72 | static inline void bswap16s(uint16_t *s) |
73 | { | |
74 | *s = bswap16(*s); | |
75 | } | |
76 | ||
77 | static inline void bswap32s(uint32_t *s) | |
78 | { | |
79 | *s = bswap32(*s); | |
80 | } | |
81 | ||
82 | static inline void bswap64s(uint64_t *s) | |
83 | { | |
84 | *s = bswap64(*s); | |
85 | } | |
86 | ||
e03b5686 | 87 | #if HOST_BIG_ENDIAN |
af8ffdfd | 88 | #define be_bswap(v, size) (v) |
a4cbfe24 | 89 | #define le_bswap(v, size) glue(bswap, size)(v) |
af8ffdfd | 90 | #define be_bswaps(v, size) |
a4cbfe24 | 91 | #define le_bswaps(p, size) do { *p = glue(bswap, size)(*p); } while(0) |
af8ffdfd FB |
92 | #else |
93 | #define le_bswap(v, size) (v) | |
a4cbfe24 | 94 | #define be_bswap(v, size) glue(bswap, size)(v) |
af8ffdfd | 95 | #define le_bswaps(v, size) |
a4cbfe24 | 96 | #define be_bswaps(p, size) do { *p = glue(bswap, size)(*p); } while(0) |
af8ffdfd FB |
97 | #endif |
98 | ||
7d820b76 PM |
99 | /** |
100 | * Endianness conversion functions between host cpu and specified endianness. | |
101 | * (We list the complete set of prototypes produced by the macros below | |
102 | * to assist people who search the headers to find their definitions.) | |
103 | * | |
104 | * uint16_t le16_to_cpu(uint16_t v); | |
105 | * uint32_t le32_to_cpu(uint32_t v); | |
106 | * uint64_t le64_to_cpu(uint64_t v); | |
107 | * uint16_t be16_to_cpu(uint16_t v); | |
108 | * uint32_t be32_to_cpu(uint32_t v); | |
109 | * uint64_t be64_to_cpu(uint64_t v); | |
110 | * | |
111 | * Convert the value @v from the specified format to the native | |
112 | * endianness of the host CPU by byteswapping if necessary, and | |
113 | * return the converted value. | |
114 | * | |
115 | * uint16_t cpu_to_le16(uint16_t v); | |
116 | * uint32_t cpu_to_le32(uint32_t v); | |
117 | * uint64_t cpu_to_le64(uint64_t v); | |
118 | * uint16_t cpu_to_be16(uint16_t v); | |
119 | * uint32_t cpu_to_be32(uint32_t v); | |
120 | * uint64_t cpu_to_be64(uint64_t v); | |
121 | * | |
122 | * Convert the value @v from the native endianness of the host CPU to | |
123 | * the specified format by byteswapping if necessary, and return | |
124 | * the converted value. | |
125 | * | |
126 | * void le16_to_cpus(uint16_t *v); | |
127 | * void le32_to_cpus(uint32_t *v); | |
128 | * void le64_to_cpus(uint64_t *v); | |
129 | * void be16_to_cpus(uint16_t *v); | |
130 | * void be32_to_cpus(uint32_t *v); | |
131 | * void be64_to_cpus(uint64_t *v); | |
132 | * | |
133 | * Do an in-place conversion of the value pointed to by @v from the | |
134 | * specified format to the native endianness of the host CPU. | |
135 | * | |
136 | * void cpu_to_le16s(uint16_t *v); | |
137 | * void cpu_to_le32s(uint32_t *v); | |
138 | * void cpu_to_le64s(uint64_t *v); | |
139 | * void cpu_to_be16s(uint16_t *v); | |
140 | * void cpu_to_be32s(uint32_t *v); | |
141 | * void cpu_to_be64s(uint64_t *v); | |
142 | * | |
143 | * Do an in-place conversion of the value pointed to by @v from the | |
144 | * native endianness of the host CPU to the specified format. | |
145 | * | |
146 | * Both X_to_cpu() and cpu_to_X() perform the same operation; you | |
147 | * should use whichever one is better documenting of the function your | |
148 | * code is performing. | |
149 | * | |
150 | * Do not use these functions for conversion of values which are in guest | |
151 | * memory, since the data may not be sufficiently aligned for the host CPU's | |
152 | * load and store instructions. Instead you should use the ld*_p() and | |
153 | * st*_p() functions, which perform loads and stores of data of any | |
154 | * required size and endianness and handle possible misalignment. | |
155 | */ | |
156 | ||
af8ffdfd FB |
157 | #define CPU_CONVERT(endian, size, type)\ |
158 | static inline type endian ## size ## _to_cpu(type v)\ | |
159 | {\ | |
a4cbfe24 | 160 | return glue(endian, _bswap)(v, size);\ |
af8ffdfd FB |
161 | }\ |
162 | \ | |
163 | static inline type cpu_to_ ## endian ## size(type v)\ | |
164 | {\ | |
a4cbfe24 | 165 | return glue(endian, _bswap)(v, size);\ |
af8ffdfd FB |
166 | }\ |
167 | \ | |
168 | static inline void endian ## size ## _to_cpus(type *p)\ | |
169 | {\ | |
a4cbfe24 | 170 | glue(endian, _bswaps)(p, size);\ |
af8ffdfd FB |
171 | }\ |
172 | \ | |
173 | static inline void cpu_to_ ## endian ## size ## s(type *p)\ | |
174 | {\ | |
a4cbfe24 | 175 | glue(endian, _bswaps)(p, size);\ |
af8ffdfd FB |
176 | } |
177 | ||
178 | CPU_CONVERT(be, 16, uint16_t) | |
179 | CPU_CONVERT(be, 32, uint32_t) | |
180 | CPU_CONVERT(be, 64, uint64_t) | |
181 | ||
182 | CPU_CONVERT(le, 16, uint16_t) | |
183 | CPU_CONVERT(le, 32, uint32_t) | |
184 | CPU_CONVERT(le, 64, uint64_t) | |
185 | ||
441330f7 | 186 | /* |
cbe967f4 | 187 | * Same as cpu_to_le{16,32}, except that gcc will figure the result is |
441330f7 GH |
188 | * a compile-time constant if you pass in a constant. So this can be |
189 | * used to initialize static variables. | |
190 | */ | |
e03b5686 | 191 | #if HOST_BIG_ENDIAN |
441330f7 GH |
192 | # define const_le32(_x) \ |
193 | ((((_x) & 0x000000ffU) << 24) | \ | |
194 | (((_x) & 0x0000ff00U) << 8) | \ | |
195 | (((_x) & 0x00ff0000U) >> 8) | \ | |
196 | (((_x) & 0xff000000U) >> 24)) | |
197 | # define const_le16(_x) \ | |
198 | ((((_x) & 0x00ff) << 8) | \ | |
199 | (((_x) & 0xff00) >> 8)) | |
200 | #else | |
201 | # define const_le32(_x) (_x) | |
202 | # define const_le16(_x) (_x) | |
203 | #endif | |
204 | ||
7db2145a RH |
205 | /* Unions for reinterpreting between floats and integers. */ |
206 | ||
cbbab922 PB |
207 | typedef union { |
208 | float32 f; | |
209 | uint32_t l; | |
210 | } CPU_FloatU; | |
211 | ||
212 | typedef union { | |
213 | float64 d; | |
e03b5686 | 214 | #if HOST_BIG_ENDIAN |
cbbab922 PB |
215 | struct { |
216 | uint32_t upper; | |
217 | uint32_t lower; | |
218 | } l; | |
219 | #else | |
220 | struct { | |
221 | uint32_t lower; | |
222 | uint32_t upper; | |
223 | } l; | |
224 | #endif | |
225 | uint64_t ll; | |
226 | } CPU_DoubleU; | |
227 | ||
228 | typedef union { | |
229 | floatx80 d; | |
230 | struct { | |
231 | uint64_t lower; | |
232 | uint16_t upper; | |
233 | } l; | |
234 | } CPU_LDoubleU; | |
235 | ||
236 | typedef union { | |
237 | float128 q; | |
e03b5686 | 238 | #if HOST_BIG_ENDIAN |
cbbab922 PB |
239 | struct { |
240 | uint32_t upmost; | |
241 | uint32_t upper; | |
242 | uint32_t lower; | |
243 | uint32_t lowest; | |
244 | } l; | |
245 | struct { | |
246 | uint64_t upper; | |
247 | uint64_t lower; | |
248 | } ll; | |
249 | #else | |
250 | struct { | |
251 | uint32_t lowest; | |
252 | uint32_t lower; | |
253 | uint32_t upper; | |
254 | uint32_t upmost; | |
255 | } l; | |
256 | struct { | |
257 | uint64_t lower; | |
258 | uint64_t upper; | |
259 | } ll; | |
260 | #endif | |
261 | } CPU_QuadU; | |
262 | ||
263 | /* unaligned/endian-independent pointer access */ | |
264 | ||
265 | /* | |
266 | * the generic syntax is: | |
267 | * | |
acfea137 | 268 | * load: ld{type}{sign}{size}_{endian}_p(ptr) |
cbbab922 | 269 | * |
acfea137 | 270 | * store: st{type}{size}_{endian}_p(ptr, val) |
cbbab922 PB |
271 | * |
272 | * Note there are small differences with the softmmu access API! | |
273 | * | |
274 | * type is: | |
275 | * (empty): integer access | |
276 | * f : float access | |
277 | * | |
278 | * sign is: | |
db5fd8d7 | 279 | * (empty): for 32 or 64 bit sizes (including floats and doubles) |
cbbab922 PB |
280 | * u : unsigned |
281 | * s : signed | |
282 | * | |
283 | * size is: | |
284 | * b: 8 bits | |
285 | * w: 16 bits | |
286 | * l: 32 bits | |
287 | * q: 64 bits | |
288 | * | |
289 | * endian is: | |
1a3de8db | 290 | * he : host endian |
cbbab922 PB |
291 | * be : big endian |
292 | * le : little endian | |
db5fd8d7 | 293 | * te : target endian |
1a3de8db | 294 | * (except for byte accesses, which have no endian infix). |
db5fd8d7 PM |
295 | * |
296 | * The target endian accessors are obviously only available to source | |
297 | * files which are built per-target; they are defined in cpu-all.h. | |
298 | * | |
299 | * In all cases these functions take a host pointer. | |
300 | * For accessors that take a guest address rather than a | |
301 | * host address, see the cpu_{ld,st}_* accessors defined in | |
302 | * cpu_ldst.h. | |
afa4f665 PM |
303 | * |
304 | * For cases where the size to be used is not fixed at compile time, | |
305 | * there are | |
acfea137 | 306 | * stn_{endian}_p(ptr, sz, val) |
afa4f665 PM |
307 | * which stores @val to @ptr as an @endian-order number @sz bytes in size |
308 | * and | |
acfea137 | 309 | * ldn_{endian}_p(ptr, sz) |
afa4f665 PM |
310 | * which loads @sz bytes from @ptr as an unsigned @endian-order number |
311 | * and returns it in a uint64_t. | |
cbbab922 | 312 | */ |
c732a52d | 313 | |
cbbab922 PB |
314 | static inline int ldub_p(const void *ptr) |
315 | { | |
316 | return *(uint8_t *)ptr; | |
317 | } | |
318 | ||
319 | static inline int ldsb_p(const void *ptr) | |
320 | { | |
321 | return *(int8_t *)ptr; | |
322 | } | |
323 | ||
0064aceb | 324 | static inline void stb_p(void *ptr, uint8_t v) |
cbbab922 PB |
325 | { |
326 | *(uint8_t *)ptr = v; | |
327 | } | |
328 | ||
77b17570 PM |
329 | /* |
330 | * Any compiler worth its salt will turn these memcpy into native unaligned | |
331 | * operations. Thus we don't need to play games with packed attributes, or | |
332 | * inline byte-by-byte stores. | |
333 | * Some compilation environments (eg some fortify-source implementations) | |
334 | * may intercept memcpy() in a way that defeats the compiler optimization, | |
335 | * though, so we use __builtin_memcpy() to give ourselves the best chance | |
336 | * of good performance. | |
337 | */ | |
7db2145a | 338 | |
1a3de8db | 339 | static inline int lduw_he_p(const void *ptr) |
7db2145a RH |
340 | { |
341 | uint16_t r; | |
77b17570 | 342 | __builtin_memcpy(&r, ptr, sizeof(r)); |
7db2145a RH |
343 | return r; |
344 | } | |
345 | ||
1a3de8db | 346 | static inline int ldsw_he_p(const void *ptr) |
7db2145a RH |
347 | { |
348 | int16_t r; | |
77b17570 | 349 | __builtin_memcpy(&r, ptr, sizeof(r)); |
7db2145a RH |
350 | return r; |
351 | } | |
352 | ||
1a3de8db | 353 | static inline void stw_he_p(void *ptr, uint16_t v) |
7db2145a | 354 | { |
77b17570 | 355 | __builtin_memcpy(ptr, &v, sizeof(v)); |
7db2145a RH |
356 | } |
357 | ||
1a3de8db | 358 | static inline int ldl_he_p(const void *ptr) |
7db2145a RH |
359 | { |
360 | int32_t r; | |
77b17570 | 361 | __builtin_memcpy(&r, ptr, sizeof(r)); |
7db2145a RH |
362 | return r; |
363 | } | |
364 | ||
1a3de8db | 365 | static inline void stl_he_p(void *ptr, uint32_t v) |
7db2145a | 366 | { |
77b17570 | 367 | __builtin_memcpy(ptr, &v, sizeof(v)); |
7db2145a RH |
368 | } |
369 | ||
1a3de8db | 370 | static inline uint64_t ldq_he_p(const void *ptr) |
7db2145a RH |
371 | { |
372 | uint64_t r; | |
77b17570 | 373 | __builtin_memcpy(&r, ptr, sizeof(r)); |
7db2145a RH |
374 | return r; |
375 | } | |
376 | ||
1a3de8db | 377 | static inline void stq_he_p(void *ptr, uint64_t v) |
7db2145a | 378 | { |
77b17570 | 379 | __builtin_memcpy(ptr, &v, sizeof(v)); |
7db2145a RH |
380 | } |
381 | ||
cbbab922 PB |
382 | static inline int lduw_le_p(const void *ptr) |
383 | { | |
1a3de8db | 384 | return (uint16_t)le_bswap(lduw_he_p(ptr), 16); |
cbbab922 PB |
385 | } |
386 | ||
387 | static inline int ldsw_le_p(const void *ptr) | |
388 | { | |
1a3de8db | 389 | return (int16_t)le_bswap(lduw_he_p(ptr), 16); |
cbbab922 PB |
390 | } |
391 | ||
392 | static inline int ldl_le_p(const void *ptr) | |
393 | { | |
1a3de8db | 394 | return le_bswap(ldl_he_p(ptr), 32); |
cbbab922 PB |
395 | } |
396 | ||
397 | static inline uint64_t ldq_le_p(const void *ptr) | |
398 | { | |
1a3de8db | 399 | return le_bswap(ldq_he_p(ptr), 64); |
cbbab922 PB |
400 | } |
401 | ||
55e7c29e | 402 | static inline void stw_le_p(void *ptr, uint16_t v) |
cbbab922 | 403 | { |
1a3de8db | 404 | stw_he_p(ptr, le_bswap(v, 16)); |
cbbab922 PB |
405 | } |
406 | ||
55e7c29e | 407 | static inline void stl_le_p(void *ptr, uint32_t v) |
cbbab922 | 408 | { |
1a3de8db | 409 | stl_he_p(ptr, le_bswap(v, 32)); |
cbbab922 PB |
410 | } |
411 | ||
412 | static inline void stq_le_p(void *ptr, uint64_t v) | |
413 | { | |
1a3de8db | 414 | stq_he_p(ptr, le_bswap(v, 64)); |
cbbab922 PB |
415 | } |
416 | ||
cbbab922 PB |
417 | static inline int lduw_be_p(const void *ptr) |
418 | { | |
1a3de8db | 419 | return (uint16_t)be_bswap(lduw_he_p(ptr), 16); |
cbbab922 PB |
420 | } |
421 | ||
422 | static inline int ldsw_be_p(const void *ptr) | |
423 | { | |
1a3de8db | 424 | return (int16_t)be_bswap(lduw_he_p(ptr), 16); |
cbbab922 PB |
425 | } |
426 | ||
427 | static inline int ldl_be_p(const void *ptr) | |
428 | { | |
1a3de8db | 429 | return be_bswap(ldl_he_p(ptr), 32); |
cbbab922 PB |
430 | } |
431 | ||
432 | static inline uint64_t ldq_be_p(const void *ptr) | |
433 | { | |
1a3de8db | 434 | return be_bswap(ldq_he_p(ptr), 64); |
cbbab922 PB |
435 | } |
436 | ||
55e7c29e | 437 | static inline void stw_be_p(void *ptr, uint16_t v) |
cbbab922 | 438 | { |
1a3de8db | 439 | stw_he_p(ptr, be_bswap(v, 16)); |
cbbab922 PB |
440 | } |
441 | ||
55e7c29e | 442 | static inline void stl_be_p(void *ptr, uint32_t v) |
cbbab922 | 443 | { |
1a3de8db | 444 | stl_he_p(ptr, be_bswap(v, 32)); |
cbbab922 PB |
445 | } |
446 | ||
447 | static inline void stq_be_p(void *ptr, uint64_t v) | |
448 | { | |
1a3de8db | 449 | stq_he_p(ptr, be_bswap(v, 64)); |
cbbab922 PB |
450 | } |
451 | ||
c732a52d RH |
452 | static inline unsigned long leul_to_cpu(unsigned long v) |
453 | { | |
a8139632 | 454 | #if HOST_LONG_BITS == 32 |
91107fdf | 455 | return le_bswap(v, 32); |
a8139632 | 456 | #elif HOST_LONG_BITS == 64 |
91107fdf RH |
457 | return le_bswap(v, 64); |
458 | #else | |
459 | # error Unknown sizeof long | |
460 | #endif | |
c732a52d RH |
461 | } |
462 | ||
afa4f665 PM |
463 | /* Store v to p as a sz byte value in host order */ |
464 | #define DO_STN_LDN_P(END) \ | |
465 | static inline void stn_## END ## _p(void *ptr, int sz, uint64_t v) \ | |
466 | { \ | |
467 | switch (sz) { \ | |
468 | case 1: \ | |
469 | stb_p(ptr, v); \ | |
470 | break; \ | |
471 | case 2: \ | |
472 | stw_ ## END ## _p(ptr, v); \ | |
473 | break; \ | |
474 | case 4: \ | |
475 | stl_ ## END ## _p(ptr, v); \ | |
476 | break; \ | |
477 | case 8: \ | |
478 | stq_ ## END ## _p(ptr, v); \ | |
479 | break; \ | |
480 | default: \ | |
481 | g_assert_not_reached(); \ | |
482 | } \ | |
483 | } \ | |
484 | static inline uint64_t ldn_## END ## _p(const void *ptr, int sz) \ | |
485 | { \ | |
486 | switch (sz) { \ | |
487 | case 1: \ | |
488 | return ldub_p(ptr); \ | |
489 | case 2: \ | |
490 | return lduw_ ## END ## _p(ptr); \ | |
491 | case 4: \ | |
492 | return (uint32_t)ldl_ ## END ## _p(ptr); \ | |
493 | case 8: \ | |
494 | return ldq_ ## END ## _p(ptr); \ | |
495 | default: \ | |
496 | g_assert_not_reached(); \ | |
497 | } \ | |
498 | } | |
499 | ||
500 | DO_STN_LDN_P(he) | |
501 | DO_STN_LDN_P(le) | |
502 | DO_STN_LDN_P(be) | |
503 | ||
504 | #undef DO_STN_LDN_P | |
505 | ||
612d590e RH |
506 | #undef le_bswap |
507 | #undef be_bswap | |
508 | #undef le_bswaps | |
509 | #undef be_bswaps | |
cbbab922 | 510 | |
b30a8c24 PM |
511 | #ifdef __cplusplus |
512 | } | |
513 | #endif | |
514 | ||
ab93bbe2 | 515 | #endif /* BSWAP_H */ |