1 /*
2 * Macros for swapping a value if the endianness is different
3 * between the target and the host.
4 *
5 * SPDX-License-Identifier: LGPL-2.1-or-later
6 */
7
8 #ifndef TSWAP_H
9 #define TSWAP_H
10
11 #include "qemu/bswap.h"
12
13 /**
14 * target_big_endian:
15 * Returns true if the (default) endianness of the target is big endian,
16 * false otherwise. Common code should normally never need to know about the
17 * endianness of the target, so please do *not* use this function unless you
18 * know very well what you are doing!
19 */
20 bool target_big_endian(void);
21 #ifdef COMPILING_PER_TARGET
22 #define target_big_endian() TARGET_BIG_ENDIAN
23 #endif
24
25 /*
26 * If we're in target-specific code, we can hard-code the swapping
27 * condition, otherwise we have to do (slower) run-time checks.
28 */
29 #ifdef COMPILING_PER_TARGET
30 #define target_needs_bswap() (HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN)
31 #else
32 #define target_needs_bswap() (HOST_BIG_ENDIAN != target_big_endian())
33 #endif /* COMPILING_PER_TARGET */
34
tswap16(uint16_t s)35 static inline uint16_t tswap16(uint16_t s)
36 {
37 if (target_needs_bswap()) {
38 return bswap16(s);
39 } else {
40 return s;
41 }
42 }
43
tswap32(uint32_t s)44 static inline uint32_t tswap32(uint32_t s)
45 {
46 if (target_needs_bswap()) {
47 return bswap32(s);
48 } else {
49 return s;
50 }
51 }
52
tswap64(uint64_t s)53 static inline uint64_t tswap64(uint64_t s)
54 {
55 if (target_needs_bswap()) {
56 return bswap64(s);
57 } else {
58 return s;
59 }
60 }
61
tswap16s(uint16_t * s)62 static inline void tswap16s(uint16_t *s)
63 {
64 if (target_needs_bswap()) {
65 *s = bswap16(*s);
66 }
67 }
68
tswap32s(uint32_t * s)69 static inline void tswap32s(uint32_t *s)
70 {
71 if (target_needs_bswap()) {
72 *s = bswap32(*s);
73 }
74 }
75
tswap64s(uint64_t * s)76 static inline void tswap64s(uint64_t *s)
77 {
78 if (target_needs_bswap()) {
79 *s = bswap64(*s);
80 }
81 }
82
83 /* Return ld{word}_{le,be}_p following target endianness. */
84 #define LOAD_IMPL(word, args...) \
85 do { \
86 if (target_big_endian()) { \
87 return glue(glue(ld, word), _be_p)(args); \
88 } else { \
89 return glue(glue(ld, word), _le_p)(args); \
90 } \
91 } while (0)
92
lduw_p(const void * ptr)93 static inline int lduw_p(const void *ptr)
94 {
95 LOAD_IMPL(uw, ptr);
96 }
97
ldsw_p(const void * ptr)98 static inline int ldsw_p(const void *ptr)
99 {
100 LOAD_IMPL(sw, ptr);
101 }
102
ldl_p(const void * ptr)103 static inline int ldl_p(const void *ptr)
104 {
105 LOAD_IMPL(l, ptr);
106 }
107
ldq_p(const void * ptr)108 static inline uint64_t ldq_p(const void *ptr)
109 {
110 LOAD_IMPL(q, ptr);
111 }
112
ldn_p(const void * ptr,int sz)113 static inline uint64_t ldn_p(const void *ptr, int sz)
114 {
115 LOAD_IMPL(n, ptr, sz);
116 }
117
118 #undef LOAD_IMPL
119
120 /* Call st{word}_{le,be}_p following target endianness. */
121 #define STORE_IMPL(word, args...) \
122 do { \
123 if (target_big_endian()) { \
124 glue(glue(st, word), _be_p)(args); \
125 } else { \
126 glue(glue(st, word), _le_p)(args); \
127 } \
128 } while (0)
129
130
stw_p(void * ptr,uint16_t v)131 static inline void stw_p(void *ptr, uint16_t v)
132 {
133 STORE_IMPL(w, ptr, v);
134 }
135
stl_p(void * ptr,uint32_t v)136 static inline void stl_p(void *ptr, uint32_t v)
137 {
138 STORE_IMPL(l, ptr, v);
139 }
140
stq_p(void * ptr,uint64_t v)141 static inline void stq_p(void *ptr, uint64_t v)
142 {
143 STORE_IMPL(q, ptr, v);
144 }
145
stn_p(void * ptr,int sz,uint64_t v)146 static inline void stn_p(void *ptr, int sz, uint64_t v)
147 {
148 STORE_IMPL(n, ptr, sz, v);
149 }
150
151 #undef STORE_IMPL
152
153 #endif /* TSWAP_H */
154