root / include / qemu / bswap.h @ a5c82852
History | View | Annotate | Download (8.1 kB)
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 |
|
17 |
static inline uint16_t bswap16(uint16_t x) |
18 |
{ |
19 |
return bswap_16(x);
|
20 |
} |
21 |
|
22 |
static inline uint32_t bswap32(uint32_t x) |
23 |
{ |
24 |
return bswap_32(x);
|
25 |
} |
26 |
|
27 |
static inline uint64_t bswap64(uint64_t x) |
28 |
{ |
29 |
return bswap_64(x);
|
30 |
} |
31 |
# else
|
32 |
static inline uint16_t bswap16(uint16_t x) |
33 |
{ |
34 |
return (((x & 0x00ff) << 8) | |
35 |
((x & 0xff00) >> 8)); |
36 |
} |
37 |
|
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 |
|
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 |
|
59 |
static inline void bswap16s(uint16_t *s) |
60 |
{ |
61 |
*s = bswap16(*s); |
62 |
} |
63 |
|
64 |
static inline void bswap32s(uint32_t *s) |
65 |
{ |
66 |
*s = bswap32(*s); |
67 |
} |
68 |
|
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 */
|
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 |
|
221 |
static inline int ldub_p(const void *ptr) |
222 |
{ |
223 |
return *(uint8_t *)ptr;
|
224 |
} |
225 |
|
226 |
static inline int ldsb_p(const void *ptr) |
227 |
{ |
228 |
return *(int8_t *)ptr;
|
229 |
} |
230 |
|
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 |
|
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 |
|
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 |
|
254 |
static inline void stw_p(void *ptr, uint16_t v) |
255 |
{ |
256 |
memcpy(ptr, &v, sizeof(v));
|
257 |
} |
258 |
|
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 |
|
266 |
static inline void stl_p(void *ptr, uint32_t v) |
267 |
{ |
268 |
memcpy(ptr, &v, sizeof(v));
|
269 |
} |
270 |
|
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 |
|
278 |
static inline void stq_p(void *ptr, uint64_t v) |
279 |
{ |
280 |
memcpy(ptr, &v, sizeof(v));
|
281 |
} |
282 |
|
283 |
static inline int lduw_le_p(const void *ptr) |
284 |
{ |
285 |
return (uint16_t)le_bswap(lduw_p(ptr), 16); |
286 |
} |
287 |
|
288 |
static inline int ldsw_le_p(const void *ptr) |
289 |
{ |
290 |
return (int16_t)le_bswap(lduw_p(ptr), 16); |
291 |
} |
292 |
|
293 |
static inline int ldl_le_p(const void *ptr) |
294 |
{ |
295 |
return le_bswap(ldl_p(ptr), 32); |
296 |
} |
297 |
|
298 |
static inline uint64_t ldq_le_p(const void *ptr) |
299 |
{ |
300 |
return le_bswap(ldq_p(ptr), 64); |
301 |
} |
302 |
|
303 |
static inline void stw_le_p(void *ptr, int v) |
304 |
{ |
305 |
stw_p(ptr, le_bswap(v, 16));
|
306 |
} |
307 |
|
308 |
static inline void stl_le_p(void *ptr, int v) |
309 |
{ |
310 |
stl_p(ptr, le_bswap(v, 32));
|
311 |
} |
312 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
348 |
static inline int lduw_be_p(const void *ptr) |
349 |
{ |
350 |
return (uint16_t)be_bswap(lduw_p(ptr), 16); |
351 |
} |
352 |
|
353 |
static inline int ldsw_be_p(const void *ptr) |
354 |
{ |
355 |
return (int16_t)be_bswap(lduw_p(ptr), 16); |
356 |
} |
357 |
|
358 |
static inline int ldl_be_p(const void *ptr) |
359 |
{ |
360 |
return be_bswap(ldl_p(ptr), 32); |
361 |
} |
362 |
|
363 |
static inline uint64_t ldq_be_p(const void *ptr) |
364 |
{ |
365 |
return be_bswap(ldq_p(ptr), 64); |
366 |
} |
367 |
|
368 |
static inline void stw_be_p(void *ptr, int v) |
369 |
{ |
370 |
stw_p(ptr, be_bswap(v, 16));
|
371 |
} |
372 |
|
373 |
static inline void stl_be_p(void *ptr, int v) |
374 |
{ |
375 |
stl_p(ptr, be_bswap(v, 32));
|
376 |
} |
377 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 */ |