1 #ifndef _ASM_GENERIC_UNALIGNED_H_ 2 #define _ASM_GENERIC_UNALIGNED_H_ 3 4 /* 5 * For the benefit of those who are trying to port Linux to another 6 * architecture, here are some C-language equivalents. 7 * 8 * This is based almost entirely upon Richard Henderson's 9 * asm-alpha/unaligned.h implementation. Some comments were 10 * taken from David Mosberger's asm-ia64/unaligned.h header. 11 */ 12 13 #include <linux/types.h> 14 15 /* 16 * The main single-value unaligned transfer routines. 17 */ 18 #define get_unaligned(ptr) \ 19 __get_unaligned((ptr), sizeof(*(ptr))) 20 #define put_unaligned(x,ptr) \ 21 ((void)sizeof(*(ptr)=(x)),\ 22 __put_unaligned((__force __u64)(x), (ptr), sizeof(*(ptr)))) 23 24 /* 25 * This function doesn't actually exist. The idea is that when 26 * someone uses the macros below with an unsupported size (datatype), 27 * the linker will alert us to the problem via an unresolved reference 28 * error. 29 */ 30 extern void bad_unaligned_access_length(void) __attribute__((noreturn)); 31 32 struct __una_u64 { __u64 x __attribute__((packed)); }; 33 struct __una_u32 { __u32 x __attribute__((packed)); }; 34 struct __una_u16 { __u16 x __attribute__((packed)); }; 35 36 /* 37 * Elemental unaligned loads 38 */ 39 40 static inline __u64 __uldq(const __u64 *addr) 41 { 42 const struct __una_u64 *ptr = (const struct __una_u64 *) addr; 43 return ptr->x; 44 } 45 46 static inline __u32 __uldl(const __u32 *addr) 47 { 48 const struct __una_u32 *ptr = (const struct __una_u32 *) addr; 49 return ptr->x; 50 } 51 52 static inline __u16 __uldw(const __u16 *addr) 53 { 54 const struct __una_u16 *ptr = (const struct __una_u16 *) addr; 55 return ptr->x; 56 } 57 58 /* 59 * Elemental unaligned stores 60 */ 61 62 static inline void __ustq(__u64 val, __u64 *addr) 63 { 64 struct __una_u64 *ptr = (struct __una_u64 *) addr; 65 ptr->x = val; 66 } 67 68 static inline void __ustl(__u32 val, __u32 *addr) 69 { 70 struct __una_u32 *ptr = (struct __una_u32 *) addr; 71 ptr->x = val; 72 } 73 74 static inline void __ustw(__u16 val, __u16 *addr) 75 { 76 struct __una_u16 *ptr = (struct __una_u16 *) addr; 77 ptr->x = val; 78 } 79 80 #define __get_unaligned(ptr, size) ({ \ 81 const void *__gu_p = ptr; \ 82 __u64 __val; \ 83 switch (size) { \ 84 case 1: \ 85 __val = *(const __u8 *)__gu_p; \ 86 break; \ 87 case 2: \ 88 __val = __uldw(__gu_p); \ 89 break; \ 90 case 4: \ 91 __val = __uldl(__gu_p); \ 92 break; \ 93 case 8: \ 94 __val = __uldq(__gu_p); \ 95 break; \ 96 default: \ 97 bad_unaligned_access_length(); \ 98 }; \ 99 (__force __typeof__(*(ptr)))__val; \ 100 }) 101 102 #define __put_unaligned(val, ptr, size) \ 103 ({ \ 104 void *__gu_p = ptr; \ 105 switch (size) { \ 106 case 1: \ 107 *(__u8 *)__gu_p = (__force __u8)val; \ 108 break; \ 109 case 2: \ 110 __ustw((__force __u16)val, __gu_p); \ 111 break; \ 112 case 4: \ 113 __ustl((__force __u32)val, __gu_p); \ 114 break; \ 115 case 8: \ 116 __ustq(val, __gu_p); \ 117 break; \ 118 default: \ 119 bad_unaligned_access_length(); \ 120 }; \ 121 (void)0; \ 122 }) 123 124 #endif /* _ASM_GENERIC_UNALIGNED_H */ 125