aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarvey Harrison <harvey.harrison@gmail.com>2008-04-29 04:03:27 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-29 11:06:27 -0400
commit064106a91be5e76cb42c1ddf5d3871e3a1bd2a23 (patch)
tree7bb3931857c933343abf9a55d663e8a9b8af13ae
parentdddfbaf8f86894415abb8256b55da68dab966ebe (diff)
kernel: add common infrastructure for unaligned access
Create a linux/unaligned directory similar in spirit to the linux/byteorder folder to hold generic implementations collected from various arches. Currently there are five implementations: 1) packed_struct.h: C-struct based, from asm-generic/unaligned.h 2) le_byteshift.h: Open coded byte-swapping, heavily based on asm-arm 3) be_byteshift.h: Open coded byte-swapping, heavily based on asm-arm 4) memmove.h: taken from multiple implementations in tree 5) access_ok.h: taken from x86 and others, unaligned access is ok. All of the new implementations checks for sizes not equal to 1,2,4,8 and will fail to link. API additions: get_unaligned_{le16|le32|le64|be16|be32|be64}(p) which is meant to replace code of the form: le16_to_cpu(get_unaligned((__le16 *)p)); put_unaligned_{le16|le32|le64|be16|be32|be64}(val, pointer) which is meant to replace code of the form: put_unaligned(cpu_to_le16(val), (__le16 *)p); The headers that arches should include from their asm/unaligned.h: access_ok.h : Wrappers of the byteswapping functions in asm/byteorder Choose a particular implementation for little-endian access: le_byteshift.h le_memmove.h (arch must be LE) le_struct.h (arch must be LE) Choose a particular implementation for big-endian access: be_byteshift.h be_memmove.h (arch must be BE) be_struct.h (arch must be BE) After including as needed from the above, include unaligned/generic.h and define your arch's get/put_unaligned as (for LE): Signed-off-by: Harvey Harrison <harvey.harrison@gmail.com> Cc: <linux-arch@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/unaligned/access_ok.h67
-rw-r--r--include/linux/unaligned/be_byteshift.h70
-rw-r--r--include/linux/unaligned/be_memmove.h36
-rw-r--r--include/linux/unaligned/be_struct.h36
-rw-r--r--include/linux/unaligned/generic.h68
-rw-r--r--include/linux/unaligned/le_byteshift.h70
-rw-r--r--include/linux/unaligned/le_memmove.h36
-rw-r--r--include/linux/unaligned/le_struct.h36
-rw-r--r--include/linux/unaligned/memmove.h45
-rw-r--r--include/linux/unaligned/packed_struct.h46
10 files changed, 510 insertions, 0 deletions
diff --git a/include/linux/unaligned/access_ok.h b/include/linux/unaligned/access_ok.h
new file mode 100644
index 000000000000..99c1b4d20b0f
--- /dev/null
+++ b/include/linux/unaligned/access_ok.h
@@ -0,0 +1,67 @@
1#ifndef _LINUX_UNALIGNED_ACCESS_OK_H
2#define _LINUX_UNALIGNED_ACCESS_OK_H
3
4#include <linux/kernel.h>
5#include <asm/byteorder.h>
6
7static inline u16 get_unaligned_le16(const void *p)
8{
9 return le16_to_cpup((__le16 *)p);
10}
11
12static inline u32 get_unaligned_le32(const void *p)
13{
14 return le32_to_cpup((__le32 *)p);
15}
16
17static inline u64 get_unaligned_le64(const void *p)
18{
19 return le64_to_cpup((__le64 *)p);
20}
21
22static inline u16 get_unaligned_be16(const void *p)
23{
24 return be16_to_cpup((__be16 *)p);
25}
26
27static inline u32 get_unaligned_be32(const void *p)
28{
29 return be32_to_cpup((__be32 *)p);
30}
31
32static inline u64 get_unaligned_be64(const void *p)
33{
34 return be64_to_cpup((__be64 *)p);
35}
36
37static inline void put_unaligned_le16(u16 val, void *p)
38{
39 *((__le16 *)p) = cpu_to_le16(val);
40}
41
42static inline void put_unaligned_le32(u32 val, void *p)
43{
44 *((__le32 *)p) = cpu_to_le32(val);
45}
46
47static inline void put_unaligned_le64(u64 val, void *p)
48{
49 *((__le64 *)p) = cpu_to_le64(val);
50}
51
52static inline void put_unaligned_be16(u16 val, void *p)
53{
54 *((__be16 *)p) = cpu_to_be16(val);
55}
56
57static inline void put_unaligned_be32(u32 val, void *p)
58{
59 *((__be32 *)p) = cpu_to_be32(val);
60}
61
62static inline void put_unaligned_be64(u64 val, void *p)
63{
64 *((__be64 *)p) = cpu_to_be64(val);
65}
66
67#endif /* _LINUX_UNALIGNED_ACCESS_OK_H */
diff --git a/include/linux/unaligned/be_byteshift.h b/include/linux/unaligned/be_byteshift.h
new file mode 100644
index 000000000000..46dd12c5709e
--- /dev/null
+++ b/include/linux/unaligned/be_byteshift.h
@@ -0,0 +1,70 @@
1#ifndef _LINUX_UNALIGNED_BE_BYTESHIFT_H
2#define _LINUX_UNALIGNED_BE_BYTESHIFT_H
3
4#include <linux/kernel.h>
5
6static inline u16 __get_unaligned_be16(const u8 *p)
7{
8 return p[0] << 8 | p[1];
9}
10
11static inline u32 __get_unaligned_be32(const u8 *p)
12{
13 return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
14}
15
16static inline u64 __get_unaligned_be64(const u8 *p)
17{
18 return (u64)__get_unaligned_be32(p) << 32 |
19 __get_unaligned_be32(p + 4);
20}
21
22static inline void __put_unaligned_be16(u16 val, u8 *p)
23{
24 *p++ = val >> 8;
25 *p++ = val;
26}
27
28static inline void __put_unaligned_be32(u32 val, u8 *p)
29{
30 __put_unaligned_be16(val >> 16, p);
31 __put_unaligned_be16(val, p + 2);
32}
33
34static inline void __put_unaligned_be64(u64 val, u8 *p)
35{
36 __put_unaligned_be32(val >> 32, p);
37 __put_unaligned_be32(val, p + 4);
38}
39
40static inline u16 get_unaligned_be16(const void *p)
41{
42 return __get_unaligned_be16((const u8 *)p);
43}
44
45static inline u32 get_unaligned_be32(const void *p)
46{
47 return __get_unaligned_be32((const u8 *)p);
48}
49
50static inline u64 get_unaligned_be64(const void *p)
51{
52 return __get_unaligned_be64((const u8 *)p);
53}
54
55static inline void put_unaligned_be16(u16 val, void *p)
56{
57 __put_unaligned_be16(val, p);
58}
59
60static inline void put_unaligned_be32(u32 val, void *p)
61{
62 __put_unaligned_be32(val, p);
63}
64
65static inline void put_unaligned_be64(u64 val, void *p)
66{
67 __put_unaligned_be64(val, p);
68}
69
70#endif /* _LINUX_UNALIGNED_BE_BYTESHIFT_H */
diff --git a/include/linux/unaligned/be_memmove.h b/include/linux/unaligned/be_memmove.h
new file mode 100644
index 000000000000..c2a76c5c9ed0
--- /dev/null
+++ b/include/linux/unaligned/be_memmove.h
@@ -0,0 +1,36 @@
1#ifndef _LINUX_UNALIGNED_BE_MEMMOVE_H
2#define _LINUX_UNALIGNED_BE_MEMMOVE_H
3
4#include <linux/unaligned/memmove.h>
5
6static inline u16 get_unaligned_be16(const void *p)
7{
8 return __get_unaligned_memmove16((const u8 *)p);
9}
10
11static inline u32 get_unaligned_be32(const void *p)
12{
13 return __get_unaligned_memmove32((const u8 *)p);
14}
15
16static inline u64 get_unaligned_be64(const void *p)
17{
18 return __get_unaligned_memmove64((const u8 *)p);
19}
20
21static inline void put_unaligned_be16(u16 val, void *p)
22{
23 __put_unaligned_memmove16(val, p);
24}
25
26static inline void put_unaligned_be32(u32 val, void *p)
27{
28 __put_unaligned_memmove32(val, p);
29}
30
31static inline void put_unaligned_be64(u64 val, void *p)
32{
33 __put_unaligned_memmove64(val, p);
34}
35
36#endif /* _LINUX_UNALIGNED_LE_MEMMOVE_H */
diff --git a/include/linux/unaligned/be_struct.h b/include/linux/unaligned/be_struct.h
new file mode 100644
index 000000000000..132415836c50
--- /dev/null
+++ b/include/linux/unaligned/be_struct.h
@@ -0,0 +1,36 @@
1#ifndef _LINUX_UNALIGNED_BE_STRUCT_H
2#define _LINUX_UNALIGNED_BE_STRUCT_H
3
4#include <linux/unaligned/packed_struct.h>
5
6static inline u16 get_unaligned_be16(const void *p)
7{
8 return __get_unaligned_cpu16((const u8 *)p);
9}
10
11static inline u32 get_unaligned_be32(const void *p)
12{
13 return __get_unaligned_cpu32((const u8 *)p);
14}
15
16static inline u64 get_unaligned_be64(const void *p)
17{
18 return __get_unaligned_cpu64((const u8 *)p);
19}
20
21static inline void put_unaligned_be16(u16 val, void *p)
22{
23 __put_unaligned_cpu16(val, p);
24}
25
26static inline void put_unaligned_be32(u32 val, void *p)
27{
28 __put_unaligned_cpu32(val, p);
29}
30
31static inline void put_unaligned_be64(u64 val, void *p)
32{
33 __put_unaligned_cpu64(val, p);
34}
35
36#endif /* _LINUX_UNALIGNED_BE_STRUCT_H */
diff --git a/include/linux/unaligned/generic.h b/include/linux/unaligned/generic.h
new file mode 100644
index 000000000000..02d97ff3df70
--- /dev/null
+++ b/include/linux/unaligned/generic.h
@@ -0,0 +1,68 @@
1#ifndef _LINUX_UNALIGNED_GENERIC_H
2#define _LINUX_UNALIGNED_GENERIC_H
3
4/*
5 * Cause a link-time error if we try an unaligned access other than
6 * 1,2,4 or 8 bytes long
7 */
8extern void __bad_unaligned_access_size(void);
9
10#define __get_unaligned_le(ptr) ((__force typeof(*(ptr)))({ \
11 __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \
12 __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_le16((ptr)), \
13 __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_le32((ptr)), \
14 __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_le64((ptr)), \
15 __bad_unaligned_access_size())))); \
16 }))
17
18#define __get_unaligned_be(ptr) ((__force typeof(*(ptr)))({ \
19 __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \
20 __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_be16((ptr)), \
21 __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_be32((ptr)), \
22 __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_be64((ptr)), \
23 __bad_unaligned_access_size())))); \
24 }))
25
26#define __put_unaligned_le(val, ptr) ({ \
27 void *__gu_p = (ptr); \
28 switch (sizeof(*(ptr))) { \
29 case 1: \
30 *(u8 *)__gu_p = (__force u8)(val); \
31 break; \
32 case 2: \
33 put_unaligned_le16((__force u16)(val), __gu_p); \
34 break; \
35 case 4: \
36 put_unaligned_le32((__force u32)(val), __gu_p); \
37 break; \
38 case 8: \
39 put_unaligned_le64((__force u64)(val), __gu_p); \
40 break; \
41 default: \
42 __bad_unaligned_access_size(); \
43 break; \
44 } \
45 (void)0; })
46
47#define __put_unaligned_be(val, ptr) ({ \
48 void *__gu_p = (ptr); \
49 switch (sizeof(*(ptr))) { \
50 case 1: \
51 *(u8 *)__gu_p = (__force u8)(val); \
52 break; \
53 case 2: \
54 put_unaligned_be16((__force u16)(val), __gu_p); \
55 break; \
56 case 4: \
57 put_unaligned_be32((__force u32)(val), __gu_p); \
58 break; \
59 case 8: \
60 put_unaligned_be64((__force u64)(val), __gu_p); \
61 break; \
62 default: \
63 __bad_unaligned_access_size(); \
64 break; \
65 } \
66 (void)0; })
67
68#endif /* _LINUX_UNALIGNED_GENERIC_H */
diff --git a/include/linux/unaligned/le_byteshift.h b/include/linux/unaligned/le_byteshift.h
new file mode 100644
index 000000000000..59777e951baf
--- /dev/null
+++ b/include/linux/unaligned/le_byteshift.h
@@ -0,0 +1,70 @@
1#ifndef _LINUX_UNALIGNED_LE_BYTESHIFT_H
2#define _LINUX_UNALIGNED_LE_BYTESHIFT_H
3
4#include <linux/kernel.h>
5
6static inline u16 __get_unaligned_le16(const u8 *p)
7{
8 return p[0] | p[1] << 8;
9}
10
11static inline u32 __get_unaligned_le32(const u8 *p)
12{
13 return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
14}
15
16static inline u64 __get_unaligned_le64(const u8 *p)
17{
18 return (u64)__get_unaligned_le32(p + 4) << 32 |
19 __get_unaligned_le32(p);
20}
21
22static inline void __put_unaligned_le16(u16 val, u8 *p)
23{
24 *p++ = val;
25 *p++ = val >> 8;
26}
27
28static inline void __put_unaligned_le32(u32 val, u8 *p)
29{
30 __put_unaligned_le16(val >> 16, p + 2);
31 __put_unaligned_le16(val, p);
32}
33
34static inline void __put_unaligned_le64(u64 val, u8 *p)
35{
36 __put_unaligned_le32(val >> 32, p + 4);
37 __put_unaligned_le32(val, p);
38}
39
40static inline u16 get_unaligned_le16(const void *p)
41{
42 return __get_unaligned_le16((const u8 *)p);
43}
44
45static inline u32 get_unaligned_le32(const void *p)
46{
47 return __get_unaligned_le32((const u8 *)p);
48}
49
50static inline u64 get_unaligned_le64(const void *p)
51{
52 return __get_unaligned_le64((const u8 *)p);
53}
54
55static inline void put_unaligned_le16(u16 val, void *p)
56{
57 __put_unaligned_le16(val, p);
58}
59
60static inline void put_unaligned_le32(u32 val, void *p)
61{
62 __put_unaligned_le32(val, p);
63}
64
65static inline void put_unaligned_le64(u64 val, void *p)
66{
67 __put_unaligned_le64(val, p);
68}
69
70#endif /* _LINUX_UNALIGNED_LE_BYTESHIFT_H */
diff --git a/include/linux/unaligned/le_memmove.h b/include/linux/unaligned/le_memmove.h
new file mode 100644
index 000000000000..269849bee4ec
--- /dev/null
+++ b/include/linux/unaligned/le_memmove.h
@@ -0,0 +1,36 @@
1#ifndef _LINUX_UNALIGNED_LE_MEMMOVE_H
2#define _LINUX_UNALIGNED_LE_MEMMOVE_H
3
4#include <linux/unaligned/memmove.h>
5
6static inline u16 get_unaligned_le16(const void *p)
7{
8 return __get_unaligned_memmove16((const u8 *)p);
9}
10
11static inline u32 get_unaligned_le32(const void *p)
12{
13 return __get_unaligned_memmove32((const u8 *)p);
14}
15
16static inline u64 get_unaligned_le64(const void *p)
17{
18 return __get_unaligned_memmove64((const u8 *)p);
19}
20
21static inline void put_unaligned_le16(u16 val, void *p)
22{
23 __put_unaligned_memmove16(val, p);
24}
25
26static inline void put_unaligned_le32(u32 val, void *p)
27{
28 __put_unaligned_memmove32(val, p);
29}
30
31static inline void put_unaligned_le64(u64 val, void *p)
32{
33 __put_unaligned_memmove64(val, p);
34}
35
36#endif /* _LINUX_UNALIGNED_LE_MEMMOVE_H */
diff --git a/include/linux/unaligned/le_struct.h b/include/linux/unaligned/le_struct.h
new file mode 100644
index 000000000000..088c4572faa8
--- /dev/null
+++ b/include/linux/unaligned/le_struct.h
@@ -0,0 +1,36 @@
1#ifndef _LINUX_UNALIGNED_LE_STRUCT_H
2#define _LINUX_UNALIGNED_LE_STRUCT_H
3
4#include <linux/unaligned/packed_struct.h>
5
6static inline u16 get_unaligned_le16(const void *p)
7{
8 return __get_unaligned_cpu16((const u8 *)p);
9}
10
11static inline u32 get_unaligned_le32(const void *p)
12{
13 return __get_unaligned_cpu32((const u8 *)p);
14}
15
16static inline u64 get_unaligned_le64(const void *p)
17{
18 return __get_unaligned_cpu64((const u8 *)p);
19}
20
21static inline void put_unaligned_le16(u16 val, void *p)
22{
23 __put_unaligned_cpu16(val, p);
24}
25
26static inline void put_unaligned_le32(u32 val, void *p)
27{
28 __put_unaligned_cpu32(val, p);
29}
30
31static inline void put_unaligned_le64(u64 val, void *p)
32{
33 __put_unaligned_cpu64(val, p);
34}
35
36#endif /* _LINUX_UNALIGNED_LE_STRUCT_H */
diff --git a/include/linux/unaligned/memmove.h b/include/linux/unaligned/memmove.h
new file mode 100644
index 000000000000..eeb5a779a4fd
--- /dev/null
+++ b/include/linux/unaligned/memmove.h
@@ -0,0 +1,45 @@
1#ifndef _LINUX_UNALIGNED_MEMMOVE_H
2#define _LINUX_UNALIGNED_MEMMOVE_H
3
4#include <linux/kernel.h>
5#include <linux/string.h>
6
7/* Use memmove here, so gcc does not insert a __builtin_memcpy. */
8
9static inline u16 __get_unaligned_memmove16(const void *p)
10{
11 u16 tmp;
12 memmove(&tmp, p, 2);
13 return tmp;
14}
15
16static inline u32 __get_unaligned_memmove32(const void *p)
17{
18 u32 tmp;
19 memmove(&tmp, p, 4);
20 return tmp;
21}
22
23static inline u64 __get_unaligned_memmove64(const void *p)
24{
25 u64 tmp;
26 memmove(&tmp, p, 8);
27 return tmp;
28}
29
30static inline void __put_unaligned_memmove16(u16 val, void *p)
31{
32 memmove(p, &val, 2);
33}
34
35static inline void __put_unaligned_memmove32(u32 val, void *p)
36{
37 memmove(p, &val, 4);
38}
39
40static inline void __put_unaligned_memmove64(u64 val, void *p)
41{
42 memmove(p, &val, 8);
43}
44
45#endif /* _LINUX_UNALIGNED_MEMMOVE_H */
diff --git a/include/linux/unaligned/packed_struct.h b/include/linux/unaligned/packed_struct.h
new file mode 100644
index 000000000000..2498bb9fe002
--- /dev/null
+++ b/include/linux/unaligned/packed_struct.h
@@ -0,0 +1,46 @@
1#ifndef _LINUX_UNALIGNED_PACKED_STRUCT_H
2#define _LINUX_UNALIGNED_PACKED_STRUCT_H
3
4#include <linux/kernel.h>
5
6struct __una_u16 { u16 x __attribute__((packed)); };
7struct __una_u32 { u32 x __attribute__((packed)); };
8struct __una_u64 { u64 x __attribute__((packed)); };
9
10static inline u16 __get_unaligned_cpu16(const void *p)
11{
12 const struct __una_u16 *ptr = (const struct __una_u16 *)p;
13 return ptr->x;
14}
15
16static inline u32 __get_unaligned_cpu32(const void *p)
17{
18 const struct __una_u32 *ptr = (const struct __una_u32 *)p;
19 return ptr->x;
20}
21
22static inline u64 __get_unaligned_cpu64(const void *p)
23{
24 const struct __una_u64 *ptr = (const struct __una_u64 *)p;
25 return ptr->x;
26}
27
28static inline void __put_unaligned_cpu16(u16 val, void *p)
29{
30 struct __una_u16 *ptr = (struct __una_u16 *)p;
31 ptr->x = val;
32}
33
34static inline void __put_unaligned_cpu32(u32 val, void *p)
35{
36 struct __una_u32 *ptr = (struct __una_u32 *)p;
37 ptr->x = val;
38}
39
40static inline void __put_unaligned_cpu64(u64 val, void *p)
41{
42 struct __una_u64 *ptr = (struct __una_u64 *)p;
43 ptr->x = val;
44}
45
46#endif /* _LINUX_UNALIGNED_PACKED_STRUCT_H */