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