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