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 19 static inline uint16_t bswap16(uint16_t x) 20 { 21 return bswap_16(x); 22 } 23 24 static inline uint32_t bswap32(uint32_t x) 25 { 26 return bswap_32(x); 27 } 28 29 static inline uint64_t bswap64(uint64_t x) 30 { 31 return bswap_64(x); 32 } 33 # else 34 static inline uint16_t bswap16(uint16_t x) 35 { 36 return (((x & 0x00ff) << 8) | 37 ((x & 0xff00) >> 8)); 38 } 39 40 static 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 48 static 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 61 static inline void bswap16s(uint16_t *s) 62 { 63 *s = bswap16(*s); 64 } 65 66 static inline void bswap32s(uint32_t *s) 67 { 68 *s = bswap32(*s); 69 } 70 71 static 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)\ 89 static inline type endian ## size ## _to_cpu(type v)\ 90 {\ 91 return glue(endian, _bswap)(v, size);\ 92 }\ 93 \ 94 static inline type cpu_to_ ## endian ## size(type v)\ 95 {\ 96 return glue(endian, _bswap)(v, size);\ 97 }\ 98 \ 99 static inline void endian ## size ## _to_cpus(type *p)\ 100 {\ 101 glue(endian, _bswaps)(p, size);\ 102 }\ 103 \ 104 static inline void cpu_to_ ## endian ## size ## s(type *p)\ 105 {\ 106 glue(endian, _bswaps)(p, size);\ 107 }\ 108 \ 109 static inline type endian ## size ## _to_cpup(const type *p)\ 110 {\ 111 return glue(glue(endian, size), _to_cpu)(*p);\ 112 }\ 113 \ 114 static inline void cpu_to_ ## endian ## size ## w(type *p, type v)\ 115 {\ 116 *p = glue(glue(cpu_to_, endian), size)(v);\ 117 } 118 119 CPU_CONVERT(be, 16, uint16_t) 120 CPU_CONVERT(be, 32, uint32_t) 121 CPU_CONVERT(be, 64, uint64_t) 122 123 CPU_CONVERT(le, 16, uint16_t) 124 CPU_CONVERT(le, 32, uint32_t) 125 CPU_CONVERT(le, 64, uint64_t) 126 127 /* len must be one of 1, 2, 4 */ 128 static 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 135 typedef union { 136 float32 f; 137 uint32_t l; 138 } CPU_FloatU; 139 140 typedef 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 156 typedef union { 157 floatx80 d; 158 struct { 159 uint64_t lower; 160 uint16_t upper; 161 } l; 162 } CPU_LDoubleU; 163 164 typedef 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 233 static inline int ldub_p(const void *ptr) 234 { 235 return *(uint8_t *)ptr; 236 } 237 238 static inline int ldsb_p(const void *ptr) 239 { 240 return *(int8_t *)ptr; 241 } 242 243 static 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 252 static inline int lduw_he_p(const void *ptr) 253 { 254 uint16_t r; 255 memcpy(&r, ptr, sizeof(r)); 256 return r; 257 } 258 259 static inline int ldsw_he_p(const void *ptr) 260 { 261 int16_t r; 262 memcpy(&r, ptr, sizeof(r)); 263 return r; 264 } 265 266 static inline void stw_he_p(void *ptr, uint16_t v) 267 { 268 memcpy(ptr, &v, sizeof(v)); 269 } 270 271 static inline int ldl_he_p(const void *ptr) 272 { 273 int32_t r; 274 memcpy(&r, ptr, sizeof(r)); 275 return r; 276 } 277 278 static inline void stl_he_p(void *ptr, uint32_t v) 279 { 280 memcpy(ptr, &v, sizeof(v)); 281 } 282 283 static 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 290 static inline void stq_he_p(void *ptr, uint64_t v) 291 { 292 memcpy(ptr, &v, sizeof(v)); 293 } 294 295 static inline int lduw_le_p(const void *ptr) 296 { 297 return (uint16_t)le_bswap(lduw_he_p(ptr), 16); 298 } 299 300 static inline int ldsw_le_p(const void *ptr) 301 { 302 return (int16_t)le_bswap(lduw_he_p(ptr), 16); 303 } 304 305 static inline int ldl_le_p(const void *ptr) 306 { 307 return le_bswap(ldl_he_p(ptr), 32); 308 } 309 310 static inline uint64_t ldq_le_p(const void *ptr) 311 { 312 return le_bswap(ldq_he_p(ptr), 64); 313 } 314 315 static inline void stw_le_p(void *ptr, uint16_t v) 316 { 317 stw_he_p(ptr, le_bswap(v, 16)); 318 } 319 320 static inline void stl_le_p(void *ptr, uint32_t v) 321 { 322 stl_he_p(ptr, le_bswap(v, 32)); 323 } 324 325 static 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 332 static 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 339 static 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 346 static 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 353 static 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 360 static inline int lduw_be_p(const void *ptr) 361 { 362 return (uint16_t)be_bswap(lduw_he_p(ptr), 16); 363 } 364 365 static inline int ldsw_be_p(const void *ptr) 366 { 367 return (int16_t)be_bswap(lduw_he_p(ptr), 16); 368 } 369 370 static inline int ldl_be_p(const void *ptr) 371 { 372 return be_bswap(ldl_he_p(ptr), 32); 373 } 374 375 static inline uint64_t ldq_be_p(const void *ptr) 376 { 377 return be_bswap(ldq_he_p(ptr), 64); 378 } 379 380 static inline void stw_be_p(void *ptr, uint16_t v) 381 { 382 stw_he_p(ptr, be_bswap(v, 16)); 383 } 384 385 static inline void stl_be_p(void *ptr, uint32_t v) 386 { 387 stl_he_p(ptr, be_bswap(v, 32)); 388 } 389 390 static 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 397 static 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 404 static 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 411 static 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 418 static 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 425 static 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