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