1 1.1 christos #ifndef ASM_UNALIGNED_H 2 1.1 christos #define ASM_UNALIGNED_H 3 1.1 christos 4 1.1 christos #include <assert.h> 5 1.1 christos #include <linux/types.h> 6 1.1 christos 7 1.1 christos #ifndef __LITTLE_ENDIAN 8 1.1 christos # if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || defined(__LITTLE_ENDIAN__) 9 1.1 christos # define __LITTLE_ENDIAN 1 10 1.1 christos # endif 11 1.1 christos #endif 12 1.1 christos 13 1.1 christos #ifdef __LITTLE_ENDIAN 14 1.1 christos # define _IS_LITTLE_ENDIAN 1 15 1.1 christos #else 16 1.1 christos # define _IS_LITTLE_ENDIAN 0 17 1.1 christos #endif 18 1.1 christos 19 1.1 christos static unsigned _isLittleEndian(void) 20 1.1 christos { 21 1.1 christos const union { uint32_t u; uint8_t c[4]; } one = { 1 }; 22 1.1 christos assert(_IS_LITTLE_ENDIAN == one.c[0]); 23 1.1 christos (void)one; 24 1.1 christos return _IS_LITTLE_ENDIAN; 25 1.1 christos } 26 1.1 christos 27 1.1 christos static uint16_t _swap16(uint16_t in) 28 1.1 christos { 29 1.1 christos return ((in & 0xF) << 8) + ((in & 0xF0) >> 8); 30 1.1 christos } 31 1.1 christos 32 1.1 christos static uint32_t _swap32(uint32_t in) 33 1.1 christos { 34 1.1 christos return __builtin_bswap32(in); 35 1.1 christos } 36 1.1 christos 37 1.1 christos static uint64_t _swap64(uint64_t in) 38 1.1 christos { 39 1.1 christos return __builtin_bswap64(in); 40 1.1 christos } 41 1.1 christos 42 1.1 christos /* Little endian */ 43 1.1 christos static uint16_t get_unaligned_le16(const void* memPtr) 44 1.1 christos { 45 1.1 christos uint16_t val; 46 1.1 christos __builtin_memcpy(&val, memPtr, sizeof(val)); 47 1.1 christos if (!_isLittleEndian()) _swap16(val); 48 1.1 christos return val; 49 1.1 christos } 50 1.1 christos 51 1.1 christos static uint32_t get_unaligned_le32(const void* memPtr) 52 1.1 christos { 53 1.1 christos uint32_t val; 54 1.1 christos __builtin_memcpy(&val, memPtr, sizeof(val)); 55 1.1 christos if (!_isLittleEndian()) _swap32(val); 56 1.1 christos return val; 57 1.1 christos } 58 1.1 christos 59 1.1 christos static uint64_t get_unaligned_le64(const void* memPtr) 60 1.1 christos { 61 1.1 christos uint64_t val; 62 1.1 christos __builtin_memcpy(&val, memPtr, sizeof(val)); 63 1.1 christos if (!_isLittleEndian()) _swap64(val); 64 1.1 christos return val; 65 1.1 christos } 66 1.1 christos 67 1.1 christos static void put_unaligned_le16(uint16_t value, void* memPtr) 68 1.1 christos { 69 1.1 christos if (!_isLittleEndian()) value = _swap16(value); 70 1.1 christos __builtin_memcpy(memPtr, &value, sizeof(value)); 71 1.1 christos } 72 1.1 christos 73 1.1 christos static void put_unaligned_le32(uint32_t value, void* memPtr) 74 1.1 christos { 75 1.1 christos if (!_isLittleEndian()) value = _swap32(value); 76 1.1 christos __builtin_memcpy(memPtr, &value, sizeof(value)); 77 1.1 christos } 78 1.1 christos 79 1.1 christos static void put_unaligned_le64(uint64_t value, void* memPtr) 80 1.1 christos { 81 1.1 christos if (!_isLittleEndian()) value = _swap64(value); 82 1.1 christos __builtin_memcpy(memPtr, &value, sizeof(value)); 83 1.1 christos } 84 1.1 christos 85 1.1 christos /* big endian */ 86 1.1 christos static uint32_t get_unaligned_be32(const void* memPtr) 87 1.1 christos { 88 1.1 christos uint32_t val; 89 1.1 christos __builtin_memcpy(&val, memPtr, sizeof(val)); 90 1.1 christos if (_isLittleEndian()) _swap32(val); 91 1.1 christos return val; 92 1.1 christos } 93 1.1 christos 94 1.1 christos static uint64_t get_unaligned_be64(const void* memPtr) 95 1.1 christos { 96 1.1 christos uint64_t val; 97 1.1 christos __builtin_memcpy(&val, memPtr, sizeof(val)); 98 1.1 christos if (_isLittleEndian()) _swap64(val); 99 1.1 christos return val; 100 1.1 christos } 101 1.1 christos 102 1.1 christos static void put_unaligned_be32(uint32_t value, void* memPtr) 103 1.1 christos { 104 1.1 christos if (_isLittleEndian()) value = _swap32(value); 105 1.1 christos __builtin_memcpy(memPtr, &value, sizeof(value)); 106 1.1 christos } 107 1.1 christos 108 1.1 christos static void put_unaligned_be64(uint64_t value, void* memPtr) 109 1.1 christos { 110 1.1 christos if (_isLittleEndian()) value = _swap64(value); 111 1.1 christos __builtin_memcpy(memPtr, &value, sizeof(value)); 112 1.1 christos } 113 1.1 christos 114 1.1 christos /* generic */ 115 1.1 christos extern void __bad_unaligned_access_size(void); 116 1.1 christos 117 1.1 christos #define __get_unaligned_le(ptr) ((typeof(*(ptr)))({ \ 118 1.1 christos __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \ 119 1.1 christos __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_le16((ptr)), \ 120 1.1 christos __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_le32((ptr)), \ 121 1.1 christos __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_le64((ptr)), \ 122 1.1 christos __bad_unaligned_access_size())))); \ 123 1.1 christos })) 124 1.1 christos 125 1.1 christos #define __get_unaligned_be(ptr) ((typeof(*(ptr)))({ \ 126 1.1 christos __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \ 127 1.1 christos __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_be16((ptr)), \ 128 1.1 christos __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_be32((ptr)), \ 129 1.1 christos __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_be64((ptr)), \ 130 1.1 christos __bad_unaligned_access_size())))); \ 131 1.1 christos })) 132 1.1 christos 133 1.1 christos #define __put_unaligned_le(val, ptr) \ 134 1.1 christos ({ \ 135 1.1 christos void *__gu_p = (ptr); \ 136 1.1 christos switch (sizeof(*(ptr))) { \ 137 1.1 christos case 1: \ 138 1.1 christos *(uint8_t *)__gu_p = (uint8_t)(val); \ 139 1.1 christos break; \ 140 1.1 christos case 2: \ 141 1.1 christos put_unaligned_le16((uint16_t)(val), __gu_p); \ 142 1.1 christos break; \ 143 1.1 christos case 4: \ 144 1.1 christos put_unaligned_le32((uint32_t)(val), __gu_p); \ 145 1.1 christos break; \ 146 1.1 christos case 8: \ 147 1.1 christos put_unaligned_le64((uint64_t)(val), __gu_p); \ 148 1.1 christos break; \ 149 1.1 christos default: \ 150 1.1 christos __bad_unaligned_access_size(); \ 151 1.1 christos break; \ 152 1.1 christos } \ 153 1.1 christos (void)0; \ 154 1.1 christos }) 155 1.1 christos 156 1.1 christos #define __put_unaligned_be(val, ptr) \ 157 1.1 christos ({ \ 158 1.1 christos void *__gu_p = (ptr); \ 159 1.1 christos switch (sizeof(*(ptr))) { \ 160 1.1 christos case 1: \ 161 1.1 christos *(uint8_t *)__gu_p = (uint8_t)(val); \ 162 1.1 christos break; \ 163 1.1 christos case 2: \ 164 1.1 christos put_unaligned_be16((uint16_t)(val), __gu_p); \ 165 1.1 christos break; \ 166 1.1 christos case 4: \ 167 1.1 christos put_unaligned_be32((uint32_t)(val), __gu_p); \ 168 1.1 christos break; \ 169 1.1 christos case 8: \ 170 1.1 christos put_unaligned_be64((uint64_t)(val), __gu_p); \ 171 1.1 christos break; \ 172 1.1 christos default: \ 173 1.1 christos __bad_unaligned_access_size(); \ 174 1.1 christos break; \ 175 1.1 christos } \ 176 1.1 christos (void)0; \ 177 1.1 christos }) 178 1.1 christos 179 1.1 christos #if _IS_LITTLE_ENDIAN 180 1.1 christos # define get_unaligned __get_unaligned_le 181 1.1 christos # define put_unaligned __put_unaligned_le 182 1.1 christos #else 183 1.1 christos # define get_unaligned __get_unaligned_be 184 1.1 christos # define put_unaligned __put_unaligned_be 185 1.1 christos #endif 186 1.1 christos 187 1.1 christos #endif // ASM_UNALIGNED_H 188