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