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