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