uaccess_64.h 5.7 KB
Newer Older
H
H. Peter Anvin 已提交
1 2
#ifndef _ASM_X86_UACCESS_64_H
#define _ASM_X86_UACCESS_64_H
L
Linus Torvalds 已提交
3 4 5 6 7 8 9

/*
 * User space memory access functions
 */
#include <linux/compiler.h>
#include <linux/errno.h>
#include <linux/prefetch.h>
10
#include <linux/lockdep.h>
L
Linus Torvalds 已提交
11 12 13 14 15 16 17
#include <asm/page.h>

/*
 * Copy To/From Userspace
 */

/* Handles exceptions in both to and from, but doesn't do access_ok */
18 19 20 21 22 23 24 25 26 27 28 29
__must_check unsigned long
copy_user_generic(void *to, const void *from, unsigned len);

__must_check unsigned long
copy_to_user(void __user *to, const void *from, unsigned len);
__must_check unsigned long
copy_from_user(void *to, const void __user *from, unsigned len);
__must_check unsigned long
copy_in_user(void __user *to, const void __user *from, unsigned len);

static __always_inline __must_check
int __copy_from_user(void *dst, const void __user *src, unsigned size)
30
{
31
	int ret = 0;
32

33
	might_fault();
L
Linus Torvalds 已提交
34
	if (!__builtin_constant_p(size))
35 36 37 38
		return copy_user_generic(dst, (__force void *)src, size);
	switch (size) {
	case 1:__get_user_asm(*(u8 *)dst, (u8 __user *)src,
			      ret, "b", "b", "=q", 1);
L
Linus Torvalds 已提交
39
		return ret;
40 41
	case 2:__get_user_asm(*(u16 *)dst, (u16 __user *)src,
			      ret, "w", "w", "=r", 2);
L
Linus Torvalds 已提交
42
		return ret;
43 44 45 46 47
	case 4:__get_user_asm(*(u32 *)dst, (u32 __user *)src,
			      ret, "l", "k", "=r", 4);
		return ret;
	case 8:__get_user_asm(*(u64 *)dst, (u64 __user *)src,
			      ret, "q", "", "=r", 8);
L
Linus Torvalds 已提交
48 49
		return ret;
	case 10:
50
		__get_user_asm(*(u64 *)dst, (u64 __user *)src,
51
			       ret, "q", "", "=r", 10);
52 53 54 55 56 57
		if (unlikely(ret))
			return ret;
		__get_user_asm(*(u16 *)(8 + (char *)dst),
			       (u16 __user *)(8 + (char __user *)src),
			       ret, "w", "w", "=r", 2);
		return ret;
L
Linus Torvalds 已提交
58
	case 16:
59 60 61 62 63 64 65 66
		__get_user_asm(*(u64 *)dst, (u64 __user *)src,
			       ret, "q", "", "=r", 16);
		if (unlikely(ret))
			return ret;
		__get_user_asm(*(u64 *)(8 + (char *)dst),
			       (u64 __user *)(8 + (char __user *)src),
			       ret, "q", "", "=r", 8);
		return ret;
L
Linus Torvalds 已提交
67
	default:
68
		return copy_user_generic(dst, (__force void *)src, size);
L
Linus Torvalds 已提交
69
	}
70
}
L
Linus Torvalds 已提交
71

72 73
static __always_inline __must_check
int __copy_to_user(void __user *dst, const void *src, unsigned size)
74
{
75
	int ret = 0;
76

77
	might_fault();
L
Linus Torvalds 已提交
78
	if (!__builtin_constant_p(size))
79 80 81 82
		return copy_user_generic((__force void *)dst, src, size);
	switch (size) {
	case 1:__put_user_asm(*(u8 *)src, (u8 __user *)dst,
			      ret, "b", "b", "iq", 1);
L
Linus Torvalds 已提交
83
		return ret;
84 85
	case 2:__put_user_asm(*(u16 *)src, (u16 __user *)dst,
			      ret, "w", "w", "ir", 2);
L
Linus Torvalds 已提交
86
		return ret;
87 88 89 90
	case 4:__put_user_asm(*(u32 *)src, (u32 __user *)dst,
			      ret, "l", "k", "ir", 4);
		return ret;
	case 8:__put_user_asm(*(u64 *)src, (u64 __user *)dst,
91
			      ret, "q", "", "er", 8);
L
Linus Torvalds 已提交
92 93
		return ret;
	case 10:
94
		__put_user_asm(*(u64 *)src, (u64 __user *)dst,
95
			       ret, "q", "", "er", 10);
96 97
		if (unlikely(ret))
			return ret;
L
Linus Torvalds 已提交
98
		asm("":::"memory");
99 100 101
		__put_user_asm(4[(u16 *)src], 4 + (u16 __user *)dst,
			       ret, "w", "w", "ir", 2);
		return ret;
L
Linus Torvalds 已提交
102
	case 16:
103
		__put_user_asm(*(u64 *)src, (u64 __user *)dst,
104
			       ret, "q", "", "er", 16);
105 106
		if (unlikely(ret))
			return ret;
L
Linus Torvalds 已提交
107
		asm("":::"memory");
108
		__put_user_asm(1[(u64 *)src], 1 + (u64 __user *)dst,
109
			       ret, "q", "", "er", 8);
110
		return ret;
L
Linus Torvalds 已提交
111
	default:
112
		return copy_user_generic((__force void *)dst, src, size);
L
Linus Torvalds 已提交
113
	}
114
}
L
Linus Torvalds 已提交
115

116 117
static __always_inline __must_check
int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
118
{
119
	int ret = 0;
120

121
	might_fault();
L
Linus Torvalds 已提交
122
	if (!__builtin_constant_p(size))
123 124 125 126
		return copy_user_generic((__force void *)dst,
					 (__force void *)src, size);
	switch (size) {
	case 1: {
L
Linus Torvalds 已提交
127
		u8 tmp;
128 129
		__get_user_asm(tmp, (u8 __user *)src,
			       ret, "b", "b", "=q", 1);
L
Linus Torvalds 已提交
130
		if (likely(!ret))
131 132
			__put_user_asm(tmp, (u8 __user *)dst,
				       ret, "b", "b", "iq", 1);
L
Linus Torvalds 已提交
133 134
		return ret;
	}
135
	case 2: {
L
Linus Torvalds 已提交
136
		u16 tmp;
137 138
		__get_user_asm(tmp, (u16 __user *)src,
			       ret, "w", "w", "=r", 2);
L
Linus Torvalds 已提交
139
		if (likely(!ret))
140 141
			__put_user_asm(tmp, (u16 __user *)dst,
				       ret, "w", "w", "ir", 2);
L
Linus Torvalds 已提交
142 143 144
		return ret;
	}

145
	case 4: {
L
Linus Torvalds 已提交
146
		u32 tmp;
147 148
		__get_user_asm(tmp, (u32 __user *)src,
			       ret, "l", "k", "=r", 4);
L
Linus Torvalds 已提交
149
		if (likely(!ret))
150 151
			__put_user_asm(tmp, (u32 __user *)dst,
				       ret, "l", "k", "ir", 4);
L
Linus Torvalds 已提交
152 153
		return ret;
	}
154
	case 8: {
L
Linus Torvalds 已提交
155
		u64 tmp;
156 157
		__get_user_asm(tmp, (u64 __user *)src,
			       ret, "q", "", "=r", 8);
L
Linus Torvalds 已提交
158
		if (likely(!ret))
159
			__put_user_asm(tmp, (u64 __user *)dst,
160
				       ret, "q", "", "er", 8);
L
Linus Torvalds 已提交
161 162 163
		return ret;
	}
	default:
164 165
		return copy_user_generic((__force void *)dst,
					 (__force void *)src, size);
L
Linus Torvalds 已提交
166
	}
167
}
L
Linus Torvalds 已提交
168

169
__must_check long
170
strncpy_from_user(char *dst, const char __user *src, long count);
171
__must_check long
172 173 174 175 176 177 178
__strncpy_from_user(char *dst, const char __user *src, long count);
__must_check long strnlen_user(const char __user *str, long n);
__must_check long __strnlen_user(const char __user *str, long n);
__must_check long strlen_user(const char __user *str);
__must_check unsigned long clear_user(void __user *mem, unsigned long len);
__must_check unsigned long __clear_user(void __user *mem, unsigned long len);

179 180
__must_check long __copy_from_user_inatomic(void *dst, const void __user *src,
					    unsigned size);
181 182 183 184 185 186

static __must_check __always_inline int
__copy_to_user_inatomic(void __user *dst, const void *src, unsigned size)
{
	return copy_user_generic((__force void *)dst, src, size);
}
L
Linus Torvalds 已提交
187

188 189
extern long __copy_user_nocache(void *dst, const void __user *src,
				unsigned size, int zerorest);
190

191 192
static inline int
__copy_from_user_nocache(void *dst, const void __user *src, unsigned size)
193 194
{
	might_sleep();
195
	return __copy_user_nocache(dst, src, size, 1);
196 197
}

198 199 200
static inline int
__copy_from_user_inatomic_nocache(void *dst, const void __user *src,
				  unsigned size)
201
{
202
	return __copy_user_nocache(dst, src, size, 0);
203 204
}

205 206 207
unsigned long
copy_user_handle_tail(char *to, char *from, unsigned len, unsigned zerorest);

H
H. Peter Anvin 已提交
208
#endif /* _ASM_X86_UACCESS_64_H */