]> git.proxmox.com Git - qemu.git/blob - include/qemu/bswap.h
b2a8f94bb469ba8f4c117e75227e67b59dc7befd
[qemu.git] / include / qemu / bswap.h
1 #ifndef BSWAP_H
2 #define BSWAP_H
3
4 #include "config-host.h"
5
6 #include <inttypes.h>
7 #include "fpu/softfloat.h"
8
9 #ifdef CONFIG_MACHINE_BSWAP_H
10 # include <sys/endian.h>
11 # include <sys/types.h>
12 # include <machine/bswap.h>
13 #elif defined(CONFIG_BYTESWAP_H)
14 # include <byteswap.h>
15
16 static inline uint16_t bswap16(uint16_t x)
17 {
18 return bswap_16(x);
19 }
20
21 static inline uint32_t bswap32(uint32_t x)
22 {
23 return bswap_32(x);
24 }
25
26 static inline uint64_t bswap64(uint64_t x)
27 {
28 return bswap_64(x);
29 }
30 # else
31 static inline uint16_t bswap16(uint16_t x)
32 {
33 return (((x & 0x00ff) << 8) |
34 ((x & 0xff00) >> 8));
35 }
36
37 static inline uint32_t bswap32(uint32_t x)
38 {
39 return (((x & 0x000000ffU) << 24) |
40 ((x & 0x0000ff00U) << 8) |
41 ((x & 0x00ff0000U) >> 8) |
42 ((x & 0xff000000U) >> 24));
43 }
44
45 static inline uint64_t bswap64(uint64_t x)
46 {
47 return (((x & 0x00000000000000ffULL) << 56) |
48 ((x & 0x000000000000ff00ULL) << 40) |
49 ((x & 0x0000000000ff0000ULL) << 24) |
50 ((x & 0x00000000ff000000ULL) << 8) |
51 ((x & 0x000000ff00000000ULL) >> 8) |
52 ((x & 0x0000ff0000000000ULL) >> 24) |
53 ((x & 0x00ff000000000000ULL) >> 40) |
54 ((x & 0xff00000000000000ULL) >> 56));
55 }
56 #endif /* ! CONFIG_MACHINE_BSWAP_H */
57
58 static inline void bswap16s(uint16_t *s)
59 {
60 *s = bswap16(*s);
61 }
62
63 static inline void bswap32s(uint32_t *s)
64 {
65 *s = bswap32(*s);
66 }
67
68 static inline void bswap64s(uint64_t *s)
69 {
70 *s = bswap64(*s);
71 }
72
73 #if defined(HOST_WORDS_BIGENDIAN)
74 #define be_bswap(v, size) (v)
75 #define le_bswap(v, size) bswap ## size(v)
76 #define be_bswaps(v, size)
77 #define le_bswaps(p, size) *p = bswap ## size(*p);
78 #else
79 #define le_bswap(v, size) (v)
80 #define be_bswap(v, size) bswap ## size(v)
81 #define le_bswaps(v, size)
82 #define be_bswaps(p, size) *p = bswap ## size(*p);
83 #endif
84
85 #define CPU_CONVERT(endian, size, type)\
86 static inline type endian ## size ## _to_cpu(type v)\
87 {\
88 return endian ## _bswap(v, size);\
89 }\
90 \
91 static inline type cpu_to_ ## endian ## size(type v)\
92 {\
93 return endian ## _bswap(v, size);\
94 }\
95 \
96 static inline void endian ## size ## _to_cpus(type *p)\
97 {\
98 endian ## _bswaps(p, size)\
99 }\
100 \
101 static inline void cpu_to_ ## endian ## size ## s(type *p)\
102 {\
103 endian ## _bswaps(p, size)\
104 }\
105 \
106 static inline type endian ## size ## _to_cpup(const type *p)\
107 {\
108 return endian ## size ## _to_cpu(*p);\
109 }\
110 \
111 static inline void cpu_to_ ## endian ## size ## w(type *p, type v)\
112 {\
113 *p = cpu_to_ ## endian ## size(v);\
114 }
115
116 CPU_CONVERT(be, 16, uint16_t)
117 CPU_CONVERT(be, 32, uint32_t)
118 CPU_CONVERT(be, 64, uint64_t)
119
120 CPU_CONVERT(le, 16, uint16_t)
121 CPU_CONVERT(le, 32, uint32_t)
122 CPU_CONVERT(le, 64, uint64_t)
123
124 /* unaligned versions (optimized for frequent unaligned accesses)*/
125
126 #if defined(__i386__) || defined(_ARCH_PPC)
127
128 #define cpu_to_le16wu(p, v) cpu_to_le16w(p, v)
129 #define cpu_to_le32wu(p, v) cpu_to_le32w(p, v)
130 #define le16_to_cpupu(p) le16_to_cpup(p)
131 #define le32_to_cpupu(p) le32_to_cpup(p)
132 #define be32_to_cpupu(p) be32_to_cpup(p)
133
134 #define cpu_to_be16wu(p, v) cpu_to_be16w(p, v)
135 #define cpu_to_be32wu(p, v) cpu_to_be32w(p, v)
136 #define cpu_to_be64wu(p, v) cpu_to_be64w(p, v)
137
138 #else
139
140 static inline void cpu_to_le16wu(uint16_t *p, uint16_t v)
141 {
142 uint8_t *p1 = (uint8_t *)p;
143
144 p1[0] = v & 0xff;
145 p1[1] = v >> 8;
146 }
147
148 static inline void cpu_to_le32wu(uint32_t *p, uint32_t v)
149 {
150 uint8_t *p1 = (uint8_t *)p;
151
152 p1[0] = v & 0xff;
153 p1[1] = v >> 8;
154 p1[2] = v >> 16;
155 p1[3] = v >> 24;
156 }
157
158 static inline uint16_t le16_to_cpupu(const uint16_t *p)
159 {
160 const uint8_t *p1 = (const uint8_t *)p;
161 return p1[0] | (p1[1] << 8);
162 }
163
164 static inline uint32_t le32_to_cpupu(const uint32_t *p)
165 {
166 const uint8_t *p1 = (const uint8_t *)p;
167 return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24);
168 }
169
170 static inline uint32_t be32_to_cpupu(const uint32_t *p)
171 {
172 const uint8_t *p1 = (const uint8_t *)p;
173 return p1[3] | (p1[2] << 8) | (p1[1] << 16) | (p1[0] << 24);
174 }
175
176 static inline void cpu_to_be16wu(uint16_t *p, uint16_t v)
177 {
178 uint8_t *p1 = (uint8_t *)p;
179
180 p1[0] = v >> 8;
181 p1[1] = v & 0xff;
182 }
183
184 static inline void cpu_to_be32wu(uint32_t *p, uint32_t v)
185 {
186 uint8_t *p1 = (uint8_t *)p;
187
188 p1[0] = v >> 24;
189 p1[1] = v >> 16;
190 p1[2] = v >> 8;
191 p1[3] = v & 0xff;
192 }
193
194 static inline void cpu_to_be64wu(uint64_t *p, uint64_t v)
195 {
196 uint8_t *p1 = (uint8_t *)p;
197
198 p1[0] = v >> 56;
199 p1[1] = v >> 48;
200 p1[2] = v >> 40;
201 p1[3] = v >> 32;
202 p1[4] = v >> 24;
203 p1[5] = v >> 16;
204 p1[6] = v >> 8;
205 p1[7] = v & 0xff;
206 }
207
208 #endif
209
210 #ifdef HOST_WORDS_BIGENDIAN
211 #define cpu_to_32wu cpu_to_be32wu
212 #define leul_to_cpu(v) glue(glue(le,HOST_LONG_BITS),_to_cpu)(v)
213 #else
214 #define cpu_to_32wu cpu_to_le32wu
215 #define leul_to_cpu(v) (v)
216 #endif
217
218 #undef le_bswap
219 #undef be_bswap
220 #undef le_bswaps
221 #undef be_bswaps
222
223 /* len must be one of 1, 2, 4 */
224 static inline uint32_t qemu_bswap_len(uint32_t value, int len)
225 {
226 return bswap32(value) >> (32 - 8 * len);
227 }
228
229 typedef union {
230 float32 f;
231 uint32_t l;
232 } CPU_FloatU;
233
234 typedef union {
235 float64 d;
236 #if defined(HOST_WORDS_BIGENDIAN)
237 struct {
238 uint32_t upper;
239 uint32_t lower;
240 } l;
241 #else
242 struct {
243 uint32_t lower;
244 uint32_t upper;
245 } l;
246 #endif
247 uint64_t ll;
248 } CPU_DoubleU;
249
250 typedef union {
251 floatx80 d;
252 struct {
253 uint64_t lower;
254 uint16_t upper;
255 } l;
256 } CPU_LDoubleU;
257
258 typedef union {
259 float128 q;
260 #if defined(HOST_WORDS_BIGENDIAN)
261 struct {
262 uint32_t upmost;
263 uint32_t upper;
264 uint32_t lower;
265 uint32_t lowest;
266 } l;
267 struct {
268 uint64_t upper;
269 uint64_t lower;
270 } ll;
271 #else
272 struct {
273 uint32_t lowest;
274 uint32_t lower;
275 uint32_t upper;
276 uint32_t upmost;
277 } l;
278 struct {
279 uint64_t lower;
280 uint64_t upper;
281 } ll;
282 #endif
283 } CPU_QuadU;
284
285 /* unaligned/endian-independent pointer access */
286
287 /*
288 * the generic syntax is:
289 *
290 * load: ld{type}{sign}{size}{endian}_p(ptr)
291 *
292 * store: st{type}{size}{endian}_p(ptr, val)
293 *
294 * Note there are small differences with the softmmu access API!
295 *
296 * type is:
297 * (empty): integer access
298 * f : float access
299 *
300 * sign is:
301 * (empty): for floats or 32 bit size
302 * u : unsigned
303 * s : signed
304 *
305 * size is:
306 * b: 8 bits
307 * w: 16 bits
308 * l: 32 bits
309 * q: 64 bits
310 *
311 * endian is:
312 * (empty): 8 bit access
313 * be : big endian
314 * le : little endian
315 */
316 static inline int ldub_p(const void *ptr)
317 {
318 return *(uint8_t *)ptr;
319 }
320
321 static inline int ldsb_p(const void *ptr)
322 {
323 return *(int8_t *)ptr;
324 }
325
326 static inline void stb_p(void *ptr, int v)
327 {
328 *(uint8_t *)ptr = v;
329 }
330
331 /* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
332 kernel handles unaligned load/stores may give better results, but
333 it is a system wide setting : bad */
334 #if defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
335
336 /* conservative code for little endian unaligned accesses */
337 static inline int lduw_le_p(const void *ptr)
338 {
339 #ifdef _ARCH_PPC
340 int val;
341 __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
342 return val;
343 #else
344 const uint8_t *p = ptr;
345 return p[0] | (p[1] << 8);
346 #endif
347 }
348
349 static inline int ldsw_le_p(const void *ptr)
350 {
351 #ifdef _ARCH_PPC
352 int val;
353 __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
354 return (int16_t)val;
355 #else
356 const uint8_t *p = ptr;
357 return (int16_t)(p[0] | (p[1] << 8));
358 #endif
359 }
360
361 static inline int ldl_le_p(const void *ptr)
362 {
363 #ifdef _ARCH_PPC
364 int val;
365 __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
366 return val;
367 #else
368 const uint8_t *p = ptr;
369 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
370 #endif
371 }
372
373 static inline uint64_t ldq_le_p(const void *ptr)
374 {
375 const uint8_t *p = ptr;
376 uint32_t v1, v2;
377 v1 = ldl_le_p(p);
378 v2 = ldl_le_p(p + 4);
379 return v1 | ((uint64_t)v2 << 32);
380 }
381
382 static inline void stw_le_p(void *ptr, int v)
383 {
384 #ifdef _ARCH_PPC
385 __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
386 #else
387 uint8_t *p = ptr;
388 p[0] = v;
389 p[1] = v >> 8;
390 #endif
391 }
392
393 static inline void stl_le_p(void *ptr, int v)
394 {
395 #ifdef _ARCH_PPC
396 __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
397 #else
398 uint8_t *p = ptr;
399 p[0] = v;
400 p[1] = v >> 8;
401 p[2] = v >> 16;
402 p[3] = v >> 24;
403 #endif
404 }
405
406 static inline void stq_le_p(void *ptr, uint64_t v)
407 {
408 uint8_t *p = ptr;
409 stl_le_p(p, (uint32_t)v);
410 stl_le_p(p + 4, v >> 32);
411 }
412
413 /* float access */
414
415 static inline float32 ldfl_le_p(const void *ptr)
416 {
417 union {
418 float32 f;
419 uint32_t i;
420 } u;
421 u.i = ldl_le_p(ptr);
422 return u.f;
423 }
424
425 static inline void stfl_le_p(void *ptr, float32 v)
426 {
427 union {
428 float32 f;
429 uint32_t i;
430 } u;
431 u.f = v;
432 stl_le_p(ptr, u.i);
433 }
434
435 static inline float64 ldfq_le_p(const void *ptr)
436 {
437 CPU_DoubleU u;
438 u.l.lower = ldl_le_p(ptr);
439 u.l.upper = ldl_le_p(ptr + 4);
440 return u.d;
441 }
442
443 static inline void stfq_le_p(void *ptr, float64 v)
444 {
445 CPU_DoubleU u;
446 u.d = v;
447 stl_le_p(ptr, u.l.lower);
448 stl_le_p(ptr + 4, u.l.upper);
449 }
450
451 #else
452
453 static inline int lduw_le_p(const void *ptr)
454 {
455 return *(uint16_t *)ptr;
456 }
457
458 static inline int ldsw_le_p(const void *ptr)
459 {
460 return *(int16_t *)ptr;
461 }
462
463 static inline int ldl_le_p(const void *ptr)
464 {
465 return *(uint32_t *)ptr;
466 }
467
468 static inline uint64_t ldq_le_p(const void *ptr)
469 {
470 return *(uint64_t *)ptr;
471 }
472
473 static inline void stw_le_p(void *ptr, int v)
474 {
475 *(uint16_t *)ptr = v;
476 }
477
478 static inline void stl_le_p(void *ptr, int v)
479 {
480 *(uint32_t *)ptr = v;
481 }
482
483 static inline void stq_le_p(void *ptr, uint64_t v)
484 {
485 *(uint64_t *)ptr = v;
486 }
487
488 /* float access */
489
490 static inline float32 ldfl_le_p(const void *ptr)
491 {
492 return *(float32 *)ptr;
493 }
494
495 static inline float64 ldfq_le_p(const void *ptr)
496 {
497 return *(float64 *)ptr;
498 }
499
500 static inline void stfl_le_p(void *ptr, float32 v)
501 {
502 *(float32 *)ptr = v;
503 }
504
505 static inline void stfq_le_p(void *ptr, float64 v)
506 {
507 *(float64 *)ptr = v;
508 }
509 #endif
510
511 #if !defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
512
513 static inline int lduw_be_p(const void *ptr)
514 {
515 #if defined(__i386__)
516 int val;
517 asm volatile ("movzwl %1, %0\n"
518 "xchgb %b0, %h0\n"
519 : "=q" (val)
520 : "m" (*(uint16_t *)ptr));
521 return val;
522 #else
523 const uint8_t *b = ptr;
524 return ((b[0] << 8) | b[1]);
525 #endif
526 }
527
528 static inline int ldsw_be_p(const void *ptr)
529 {
530 #if defined(__i386__)
531 int val;
532 asm volatile ("movzwl %1, %0\n"
533 "xchgb %b0, %h0\n"
534 : "=q" (val)
535 : "m" (*(uint16_t *)ptr));
536 return (int16_t)val;
537 #else
538 const uint8_t *b = ptr;
539 return (int16_t)((b[0] << 8) | b[1]);
540 #endif
541 }
542
543 static inline int ldl_be_p(const void *ptr)
544 {
545 #if defined(__i386__) || defined(__x86_64__)
546 int val;
547 asm volatile ("movl %1, %0\n"
548 "bswap %0\n"
549 : "=r" (val)
550 : "m" (*(uint32_t *)ptr));
551 return val;
552 #else
553 const uint8_t *b = ptr;
554 return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
555 #endif
556 }
557
558 static inline uint64_t ldq_be_p(const void *ptr)
559 {
560 uint32_t a,b;
561 a = ldl_be_p(ptr);
562 b = ldl_be_p((uint8_t *)ptr + 4);
563 return (((uint64_t)a<<32)|b);
564 }
565
566 static inline void stw_be_p(void *ptr, int v)
567 {
568 #if defined(__i386__)
569 asm volatile ("xchgb %b0, %h0\n"
570 "movw %w0, %1\n"
571 : "=q" (v)
572 : "m" (*(uint16_t *)ptr), "0" (v));
573 #else
574 uint8_t *d = (uint8_t *) ptr;
575 d[0] = v >> 8;
576 d[1] = v;
577 #endif
578 }
579
580 static inline void stl_be_p(void *ptr, int v)
581 {
582 #if defined(__i386__) || defined(__x86_64__)
583 asm volatile ("bswap %0\n"
584 "movl %0, %1\n"
585 : "=r" (v)
586 : "m" (*(uint32_t *)ptr), "0" (v));
587 #else
588 uint8_t *d = (uint8_t *) ptr;
589 d[0] = v >> 24;
590 d[1] = v >> 16;
591 d[2] = v >> 8;
592 d[3] = v;
593 #endif
594 }
595
596 static inline void stq_be_p(void *ptr, uint64_t v)
597 {
598 stl_be_p(ptr, v >> 32);
599 stl_be_p((uint8_t *)ptr + 4, v);
600 }
601
602 /* float access */
603
604 static inline float32 ldfl_be_p(const void *ptr)
605 {
606 union {
607 float32 f;
608 uint32_t i;
609 } u;
610 u.i = ldl_be_p(ptr);
611 return u.f;
612 }
613
614 static inline void stfl_be_p(void *ptr, float32 v)
615 {
616 union {
617 float32 f;
618 uint32_t i;
619 } u;
620 u.f = v;
621 stl_be_p(ptr, u.i);
622 }
623
624 static inline float64 ldfq_be_p(const void *ptr)
625 {
626 CPU_DoubleU u;
627 u.l.upper = ldl_be_p(ptr);
628 u.l.lower = ldl_be_p((uint8_t *)ptr + 4);
629 return u.d;
630 }
631
632 static inline void stfq_be_p(void *ptr, float64 v)
633 {
634 CPU_DoubleU u;
635 u.d = v;
636 stl_be_p(ptr, u.l.upper);
637 stl_be_p((uint8_t *)ptr + 4, u.l.lower);
638 }
639
640 #else
641
642 static inline int lduw_be_p(const void *ptr)
643 {
644 return *(uint16_t *)ptr;
645 }
646
647 static inline int ldsw_be_p(const void *ptr)
648 {
649 return *(int16_t *)ptr;
650 }
651
652 static inline int ldl_be_p(const void *ptr)
653 {
654 return *(uint32_t *)ptr;
655 }
656
657 static inline uint64_t ldq_be_p(const void *ptr)
658 {
659 return *(uint64_t *)ptr;
660 }
661
662 static inline void stw_be_p(void *ptr, int v)
663 {
664 *(uint16_t *)ptr = v;
665 }
666
667 static inline void stl_be_p(void *ptr, int v)
668 {
669 *(uint32_t *)ptr = v;
670 }
671
672 static inline void stq_be_p(void *ptr, uint64_t v)
673 {
674 *(uint64_t *)ptr = v;
675 }
676
677 /* float access */
678
679 static inline float32 ldfl_be_p(const void *ptr)
680 {
681 return *(float32 *)ptr;
682 }
683
684 static inline float64 ldfq_be_p(const void *ptr)
685 {
686 return *(float64 *)ptr;
687 }
688
689 static inline void stfl_be_p(void *ptr, float32 v)
690 {
691 *(float32 *)ptr = v;
692 }
693
694 static inline void stfq_be_p(void *ptr, float64 v)
695 {
696 *(float64 *)ptr = v;
697 }
698
699 #endif
700
701 #endif /* BSWAP_H */