• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef BSWAP_H
2 #define BSWAP_H
3 
4 #include "config-host.h"
5 #include <inttypes.h>
6 #include <limits.h>
7 #include <string.h>
8 #include "fpu/softfloat.h"
9 
10 #ifdef CONFIG_MACHINE_BSWAP_H
11 # include <sys/endian.h>
12 # include <sys/types.h>
13 # include <machine/bswap.h>
14 #elif defined(CONFIG_BYTESWAP_H)
15 # include <byteswap.h>
16 
bswap16(uint16_t x)17 static inline uint16_t bswap16(uint16_t x)
18 {
19     return bswap_16(x);
20 }
21 
bswap32(uint32_t x)22 static inline uint32_t bswap32(uint32_t x)
23 {
24     return bswap_32(x);
25 }
26 
bswap64(uint64_t x)27 static inline uint64_t bswap64(uint64_t x)
28 {
29     return bswap_64(x);
30 }
31 # else
bswap16(uint16_t x)32 static inline uint16_t bswap16(uint16_t x)
33 {
34     return (((x & 0x00ff) << 8) |
35             ((x & 0xff00) >> 8));
36 }
37 
bswap32(uint32_t x)38 static inline uint32_t bswap32(uint32_t x)
39 {
40     return (((x & 0x000000ffU) << 24) |
41             ((x & 0x0000ff00U) <<  8) |
42             ((x & 0x00ff0000U) >>  8) |
43             ((x & 0xff000000U) >> 24));
44 }
45 
bswap64(uint64_t x)46 static inline uint64_t bswap64(uint64_t x)
47 {
48     return (((x & 0x00000000000000ffULL) << 56) |
49             ((x & 0x000000000000ff00ULL) << 40) |
50             ((x & 0x0000000000ff0000ULL) << 24) |
51             ((x & 0x00000000ff000000ULL) <<  8) |
52             ((x & 0x000000ff00000000ULL) >>  8) |
53             ((x & 0x0000ff0000000000ULL) >> 24) |
54             ((x & 0x00ff000000000000ULL) >> 40) |
55             ((x & 0xff00000000000000ULL) >> 56));
56 }
57 #endif /* ! CONFIG_MACHINE_BSWAP_H */
58 
bswap16s(uint16_t * s)59 static inline void bswap16s(uint16_t *s)
60 {
61     *s = bswap16(*s);
62 }
63 
bswap32s(uint32_t * s)64 static inline void bswap32s(uint32_t *s)
65 {
66     *s = bswap32(*s);
67 }
68 
bswap64s(uint64_t * s)69 static inline void bswap64s(uint64_t *s)
70 {
71     *s = bswap64(*s);
72 }
73 
74 #if defined(HOST_WORDS_BIGENDIAN)
75 #define be_bswap(v, size) (v)
76 #define le_bswap(v, size) glue(bswap, size)(v)
77 #define be_bswaps(v, size)
78 #define le_bswaps(p, size) do { *p = glue(bswap, size)(*p); } while(0)
79 #else
80 #define le_bswap(v, size) (v)
81 #define be_bswap(v, size) glue(bswap, size)(v)
82 #define le_bswaps(v, size)
83 #define be_bswaps(p, size) do { *p = glue(bswap, size)(*p); } while(0)
84 #endif
85 
86 #define CPU_CONVERT(endian, size, type)\
87 static inline type endian ## size ## _to_cpu(type v)\
88 {\
89     return glue(endian, _bswap)(v, size);\
90 }\
91 \
92 static inline type cpu_to_ ## endian ## size(type v)\
93 {\
94     return glue(endian, _bswap)(v, size);\
95 }\
96 \
97 static inline void endian ## size ## _to_cpus(type *p)\
98 {\
99     glue(endian, _bswaps)(p, size);\
100 }\
101 \
102 static inline void cpu_to_ ## endian ## size ## s(type *p)\
103 {\
104     glue(endian, _bswaps)(p, size);\
105 }\
106 \
107 static inline type endian ## size ## _to_cpup(const type *p)\
108 {\
109     return glue(glue(endian, size), _to_cpu)(*p);\
110 }\
111 \
112 static inline void cpu_to_ ## endian ## size ## w(type *p, type v)\
113 {\
114     *p = glue(glue(cpu_to_, endian), size)(v);\
115 }
116 
117 CPU_CONVERT(be, 16, uint16_t)
118 CPU_CONVERT(be, 32, uint32_t)
119 CPU_CONVERT(be, 64, uint64_t)
120 
121 CPU_CONVERT(le, 16, uint16_t)
122 CPU_CONVERT(le, 32, uint32_t)
123 CPU_CONVERT(le, 64, uint64_t)
124 
125 /* len must be one of 1, 2, 4 */
qemu_bswap_len(uint32_t value,int len)126 static inline uint32_t qemu_bswap_len(uint32_t value, int len)
127 {
128     return bswap32(value) >> (32 - 8 * len);
129 }
130 
131 /* Unions for reinterpreting between floats and integers.  */
132 
133 typedef union {
134     float32 f;
135     uint32_t l;
136 } CPU_FloatU;
137 
138 typedef union {
139     float64 d;
140 #if defined(HOST_WORDS_BIGENDIAN)
141     struct {
142         uint32_t upper;
143         uint32_t lower;
144     } l;
145 #else
146     struct {
147         uint32_t lower;
148         uint32_t upper;
149     } l;
150 #endif
151     uint64_t ll;
152 } CPU_DoubleU;
153 
154 typedef union {
155      floatx80 d;
156      struct {
157          uint64_t lower;
158          uint16_t upper;
159      } l;
160 } CPU_LDoubleU;
161 
162 typedef union {
163     float128 q;
164 #if defined(HOST_WORDS_BIGENDIAN)
165     struct {
166         uint32_t upmost;
167         uint32_t upper;
168         uint32_t lower;
169         uint32_t lowest;
170     } l;
171     struct {
172         uint64_t upper;
173         uint64_t lower;
174     } ll;
175 #else
176     struct {
177         uint32_t lowest;
178         uint32_t lower;
179         uint32_t upper;
180         uint32_t upmost;
181     } l;
182     struct {
183         uint64_t lower;
184         uint64_t upper;
185     } ll;
186 #endif
187 } CPU_QuadU;
188 
189 /* unaligned/endian-independent pointer access */
190 
191 /*
192  * the generic syntax is:
193  *
194  * load: ld{type}{sign}{size}{endian}_p(ptr)
195  *
196  * store: st{type}{size}{endian}_p(ptr, val)
197  *
198  * Note there are small differences with the softmmu access API!
199  *
200  * type is:
201  * (empty): integer access
202  *   f    : float access
203  *
204  * sign is:
205  * (empty): for floats or 32 bit size
206  *   u    : unsigned
207  *   s    : signed
208  *
209  * size is:
210  *   b: 8 bits
211  *   w: 16 bits
212  *   l: 32 bits
213  *   q: 64 bits
214  *
215  * endian is:
216  * (empty): host endian
217  *   be   : big endian
218  *   le   : little endian
219  */
220 
ldub_p(const void * ptr)221 static inline int ldub_p(const void *ptr)
222 {
223     return *(uint8_t *)ptr;
224 }
225 
ldsb_p(const void * ptr)226 static inline int ldsb_p(const void *ptr)
227 {
228     return *(int8_t *)ptr;
229 }
230 
stb_p(void * ptr,int v)231 static inline void stb_p(void *ptr, int v)
232 {
233     *(uint8_t *)ptr = v;
234 }
235 
236 /* Any compiler worth its salt will turn these memcpy into native unaligned
237    operations.  Thus we don't need to play games with packed attributes, or
238    inline byte-by-byte stores.  */
239 
lduw_p(const void * ptr)240 static inline int lduw_p(const void *ptr)
241 {
242     uint16_t r;
243     memcpy(&r, ptr, sizeof(r));
244     return r;
245 }
246 
ldsw_p(const void * ptr)247 static inline int ldsw_p(const void *ptr)
248 {
249     int16_t r;
250     memcpy(&r, ptr, sizeof(r));
251     return r;
252 }
253 
stw_p(void * ptr,uint16_t v)254 static inline void stw_p(void *ptr, uint16_t v)
255 {
256     memcpy(ptr, &v, sizeof(v));
257 }
258 
ldl_p(const void * ptr)259 static inline int ldl_p(const void *ptr)
260 {
261     int32_t r;
262     memcpy(&r, ptr, sizeof(r));
263     return r;
264 }
265 
stl_p(void * ptr,uint32_t v)266 static inline void stl_p(void *ptr, uint32_t v)
267 {
268     memcpy(ptr, &v, sizeof(v));
269 }
270 
ldq_p(const void * ptr)271 static inline uint64_t ldq_p(const void *ptr)
272 {
273     uint64_t r;
274     memcpy(&r, ptr, sizeof(r));
275     return r;
276 }
277 
stq_p(void * ptr,uint64_t v)278 static inline void stq_p(void *ptr, uint64_t v)
279 {
280     memcpy(ptr, &v, sizeof(v));
281 }
282 
lduw_le_p(const void * ptr)283 static inline int lduw_le_p(const void *ptr)
284 {
285     return (uint16_t)le_bswap(lduw_p(ptr), 16);
286 }
287 
ldsw_le_p(const void * ptr)288 static inline int ldsw_le_p(const void *ptr)
289 {
290     return (int16_t)le_bswap(lduw_p(ptr), 16);
291 }
292 
ldl_le_p(const void * ptr)293 static inline int ldl_le_p(const void *ptr)
294 {
295     return le_bswap(ldl_p(ptr), 32);
296 }
297 
ldq_le_p(const void * ptr)298 static inline uint64_t ldq_le_p(const void *ptr)
299 {
300     return le_bswap(ldq_p(ptr), 64);
301 }
302 
stw_le_p(void * ptr,int v)303 static inline void stw_le_p(void *ptr, int v)
304 {
305     stw_p(ptr, le_bswap(v, 16));
306 }
307 
stl_le_p(void * ptr,int v)308 static inline void stl_le_p(void *ptr, int v)
309 {
310     stl_p(ptr, le_bswap(v, 32));
311 }
312 
stq_le_p(void * ptr,uint64_t v)313 static inline void stq_le_p(void *ptr, uint64_t v)
314 {
315     stq_p(ptr, le_bswap(v, 64));
316 }
317 
318 /* float access */
319 
ldfl_le_p(const void * ptr)320 static inline float32 ldfl_le_p(const void *ptr)
321 {
322     CPU_FloatU u;
323     u.l = ldl_le_p(ptr);
324     return u.f;
325 }
326 
stfl_le_p(void * ptr,float32 v)327 static inline void stfl_le_p(void *ptr, float32 v)
328 {
329     CPU_FloatU u;
330     u.f = v;
331     stl_le_p(ptr, u.l);
332 }
333 
ldfq_le_p(const void * ptr)334 static inline float64 ldfq_le_p(const void *ptr)
335 {
336     CPU_DoubleU u;
337     u.ll = ldq_le_p(ptr);
338     return u.d;
339 }
340 
stfq_le_p(void * ptr,float64 v)341 static inline void stfq_le_p(void *ptr, float64 v)
342 {
343     CPU_DoubleU u;
344     u.d = v;
345     stq_le_p(ptr, u.ll);
346 }
347 
lduw_be_p(const void * ptr)348 static inline int lduw_be_p(const void *ptr)
349 {
350     return (uint16_t)be_bswap(lduw_p(ptr), 16);
351 }
352 
ldsw_be_p(const void * ptr)353 static inline int ldsw_be_p(const void *ptr)
354 {
355     return (int16_t)be_bswap(lduw_p(ptr), 16);
356 }
357 
ldl_be_p(const void * ptr)358 static inline int ldl_be_p(const void *ptr)
359 {
360     return be_bswap(ldl_p(ptr), 32);
361 }
362 
ldq_be_p(const void * ptr)363 static inline uint64_t ldq_be_p(const void *ptr)
364 {
365     return be_bswap(ldq_p(ptr), 64);
366 }
367 
stw_be_p(void * ptr,int v)368 static inline void stw_be_p(void *ptr, int v)
369 {
370     stw_p(ptr, be_bswap(v, 16));
371 }
372 
stl_be_p(void * ptr,int v)373 static inline void stl_be_p(void *ptr, int v)
374 {
375     stl_p(ptr, be_bswap(v, 32));
376 }
377 
stq_be_p(void * ptr,uint64_t v)378 static inline void stq_be_p(void *ptr, uint64_t v)
379 {
380     stq_p(ptr, be_bswap(v, 64));
381 }
382 
383 /* float access */
384 
ldfl_be_p(const void * ptr)385 static inline float32 ldfl_be_p(const void *ptr)
386 {
387     CPU_FloatU u;
388     u.l = ldl_be_p(ptr);
389     return u.f;
390 }
391 
stfl_be_p(void * ptr,float32 v)392 static inline void stfl_be_p(void *ptr, float32 v)
393 {
394     CPU_FloatU u;
395     u.f = v;
396     stl_be_p(ptr, u.l);
397 }
398 
ldfq_be_p(const void * ptr)399 static inline float64 ldfq_be_p(const void *ptr)
400 {
401     CPU_DoubleU u;
402     u.ll = ldq_be_p(ptr);
403     return u.d;
404 }
405 
stfq_be_p(void * ptr,float64 v)406 static inline void stfq_be_p(void *ptr, float64 v)
407 {
408     CPU_DoubleU u;
409     u.d = v;
410     stq_be_p(ptr, u.ll);
411 }
412 
leul_to_cpu(unsigned long v)413 static inline unsigned long leul_to_cpu(unsigned long v)
414 {
415     /* In order to break an include loop between here and
416        qemu-common.h, don't rely on HOST_LONG_BITS.  */
417 #if ULONG_MAX == UINT32_MAX
418     return le_bswap(v, 32);
419 #elif ULONG_MAX == UINT64_MAX
420     return le_bswap(v, 64);
421 #else
422 # error Unknown sizeof long
423 #endif
424 }
425 
426 #undef le_bswap
427 #undef be_bswap
428 #undef le_bswaps
429 #undef be_bswaps
430 
431 #endif /* BSWAP_H */
432