2fe1b2e67f0121b96d0a60f129fcc9f14972c937
[linux-3.10.git] / include / asm-generic / unaligned.h
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 */