File: unaligned.h

package info (click to toggle)
linux-kernel-headers 2.5.999-test7-bk-17
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 28,268 kB
  • ctags: 214,024
  • sloc: ansic: 324,929; cpp: 783; makefile: 79; asm: 61; sh: 61
file content (144 lines) | stat: -rw-r--r-- 3,421 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (C) 1996, 1999, 2000, 2001, 2003 by Ralf Baechle
 * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc.
 */
#ifndef _ASM_UNALIGNED_H
#define _ASM_UNALIGNED_H

#include <linux/types.h>

/*
 * get_unaligned - get value from possibly mis-aligned location
 * @ptr: pointer to value
 *
 * This macro should be used for accessing values larger in size than
 * single bytes at locations that are expected to be improperly aligned,
 * e.g. retrieving a u16 value from a location not u16-aligned.
 *
 * Note that unaligned accesses can be very expensive on some architectures.
 */
#define get_unaligned(ptr) \
	((__typeof__(*(ptr)))__get_unaligned((ptr), sizeof(*(ptr))))

/*
 * put_unaligned - put value to a possibly mis-aligned location
 * @val: value to place
 * @ptr: pointer to location
 *
 * This macro should be used for placing values larger in size than
 * single bytes at locations that are expected to be improperly aligned,
 * e.g. writing a u16 value to a location not u16-aligned.
 *
 * Note that unaligned accesses can be very expensive on some architectures.
 */
#define put_unaligned(x,ptr) \
	__put_unaligned((__u64)(x), (ptr), sizeof(*(ptr)))

/*
 * This is a silly but good way to make sure that
 * the get/put functions are indeed always optimized,
 * and that we use the correct sizes.
 */
extern void bad_unaligned_access_length(void);

/*
 * EGCS 1.1 knows about arbitrary unaligned loads.  Define some
 * packed structures to talk about such things with.
 */

struct __una_u64 { __u64 x __attribute__((packed)); };
struct __una_u32 { __u32 x __attribute__((packed)); };
struct __una_u16 { __u16 x __attribute__((packed)); };

/*
 * Elemental unaligned loads 
 */

extern inline __u64 __uldq(const __u64 * r11)
{
	const struct __una_u64 *ptr = (const struct __una_u64 *) r11;
	return ptr->x;
}

extern inline __u32 __uldl(const __u32 * r11)
{
	const struct __una_u32 *ptr = (const struct __una_u32 *) r11;
	return ptr->x;
}

extern inline __u16 __uldw(const __u16 * r11)
{
	const struct __una_u16 *ptr = (const struct __una_u16 *) r11;
	return ptr->x;
}

/*
 * Elemental unaligned stores 
 */

extern inline void __ustq(__u64 r5, __u64 * r11)
{
	struct __una_u64 *ptr = (struct __una_u64 *) r11;
	ptr->x = r5;
}

extern inline void __ustl(__u32 r5, __u32 * r11)
{
	struct __una_u32 *ptr = (struct __una_u32 *) r11;
	ptr->x = r5;
}

extern inline void __ustw(__u16 r5, __u16 * r11)
{
	struct __una_u16 *ptr = (struct __una_u16 *) r11;
	ptr->x = r5;
}

extern inline __u64 __get_unaligned(const void *ptr, size_t size)
{
	__u64 val;

	switch (size) {
	case 1:
		val = *(const __u8 *)ptr;
		break;
	case 2:
		val = __uldw((const __u16 *)ptr);
		break;
	case 4:
		val = __uldl((const __u32 *)ptr);
		break;
	case 8:
		val = __uldq((const __u64 *)ptr);
		break;
	default:
		bad_unaligned_access_length();
	}
	return val;
}

extern inline void __put_unaligned(__u64 val, void *ptr, size_t size)
{
	switch (size) {
	      case 1:
		*(__u8 *)ptr = (val);
	        break;
	      case 2:
		__ustw(val, (__u16 *)ptr);
		break;
	      case 4:
		__ustl(val, (__u32 *)ptr);
		break;
	      case 8:
		__ustq(val, (__u64 *)ptr);
		break;
	      default:
	    	bad_unaligned_access_length();
	}
}

#endif /* _ASM_UNALIGNED_H */