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