Home | History | Annotate | Download | only in qemu
      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 */
    432