Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/microblaze/include/asm/uaccess.h
26439 views
1
/* SPDX-License-Identifier: GPL-2.0 */
2
/*
3
* Copyright (C) 2008-2009 Michal Simek <[email protected]>
4
* Copyright (C) 2008-2009 PetaLogix
5
* Copyright (C) 2006 Atmark Techno, Inc.
6
*/
7
8
#ifndef _ASM_MICROBLAZE_UACCESS_H
9
#define _ASM_MICROBLAZE_UACCESS_H
10
11
#include <linux/kernel.h>
12
13
#include <asm/mmu.h>
14
#include <asm/page.h>
15
#include <linux/pgtable.h>
16
#include <asm/extable.h>
17
#include <linux/string.h>
18
#include <asm-generic/access_ok.h>
19
20
# define __FIXUP_SECTION ".section .fixup,\"ax\"\n"
21
# define __EX_TABLE_SECTION ".section __ex_table,\"a\"\n"
22
23
extern unsigned long __copy_tofrom_user(void __user *to,
24
const void __user *from, unsigned long size);
25
26
/* Return: number of not copied bytes, i.e. 0 if OK or non-zero if fail. */
27
static inline unsigned long __must_check __clear_user(void __user *to,
28
unsigned long n)
29
{
30
/* normal memset with two words to __ex_table */
31
__asm__ __volatile__ ( \
32
"1: sb r0, %1, r0;" \
33
" addik %0, %0, -1;" \
34
" bneid %0, 1b;" \
35
" addik %1, %1, 1;" \
36
"2: " \
37
__EX_TABLE_SECTION \
38
".word 1b,2b;" \
39
".previous;" \
40
: "=r"(n), "=r"(to) \
41
: "0"(n), "1"(to)
42
);
43
return n;
44
}
45
46
static inline unsigned long __must_check clear_user(void __user *to,
47
unsigned long n)
48
{
49
might_fault();
50
if (unlikely(!access_ok(to, n)))
51
return n;
52
53
return __clear_user(to, n);
54
}
55
56
/* put_user and get_user macros */
57
extern long __user_bad(void);
58
59
#define __get_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \
60
({ \
61
__asm__ __volatile__ ( \
62
"1:" insn " %1, %2, r0;" \
63
" addk %0, r0, r0;" \
64
"2: " \
65
__FIXUP_SECTION \
66
"3: brid 2b;" \
67
" addik %0, r0, %3;" \
68
".previous;" \
69
__EX_TABLE_SECTION \
70
".word 1b,3b;" \
71
".previous;" \
72
: "=&r"(__gu_err), "=r"(__gu_val) \
73
: "r"(__gu_ptr), "i"(-EFAULT) \
74
); \
75
})
76
77
/**
78
* get_user: - Get a simple variable from user space.
79
* @x: Variable to store result.
80
* @ptr: Source address, in user space.
81
*
82
* Context: User context only. This function may sleep if pagefaults are
83
* enabled.
84
*
85
* This macro copies a single simple variable from user space to kernel
86
* space. It supports simple types like char and int, but not larger
87
* data types like structures or arrays.
88
*
89
* @ptr must have pointer-to-simple-variable type, and the result of
90
* dereferencing @ptr must be assignable to @x without a cast.
91
*
92
* Returns zero on success, or -EFAULT on error.
93
* On error, the variable @x is set to zero.
94
*/
95
#define get_user(x, ptr) ({ \
96
const typeof(*(ptr)) __user *__gu_ptr = (ptr); \
97
access_ok(__gu_ptr, sizeof(*__gu_ptr)) ? \
98
__get_user(x, __gu_ptr) : -EFAULT; \
99
})
100
101
#define __get_user(x, ptr) \
102
({ \
103
long __gu_err; \
104
switch (sizeof(*(ptr))) { \
105
case 1: \
106
__get_user_asm("lbu", (ptr), x, __gu_err); \
107
break; \
108
case 2: \
109
__get_user_asm("lhu", (ptr), x, __gu_err); \
110
break; \
111
case 4: \
112
__get_user_asm("lw", (ptr), x, __gu_err); \
113
break; \
114
case 8: { \
115
__u64 __x = 0; \
116
__gu_err = raw_copy_from_user(&__x, ptr, 8) ? \
117
-EFAULT : 0; \
118
(x) = (typeof(x))(typeof((x) - (x)))__x; \
119
break; \
120
} \
121
default: \
122
/* __gu_val = 0; __gu_err = -EINVAL;*/ __gu_err = __user_bad();\
123
} \
124
__gu_err; \
125
})
126
127
128
#define __put_user_asm(insn, __gu_ptr, __gu_val, __gu_err) \
129
({ \
130
__asm__ __volatile__ ( \
131
"1:" insn " %1, %2, r0;" \
132
" addk %0, r0, r0;" \
133
"2: " \
134
__FIXUP_SECTION \
135
"3: brid 2b;" \
136
" addik %0, r0, %3;" \
137
".previous;" \
138
__EX_TABLE_SECTION \
139
".word 1b,3b;" \
140
".previous;" \
141
: "=&r"(__gu_err) \
142
: "r"(__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \
143
); \
144
})
145
146
#define __put_user_asm_8(__gu_ptr, __gu_val, __gu_err) \
147
({ \
148
__asm__ __volatile__ (" lwi %0, %1, 0;" \
149
"1: swi %0, %2, 0;" \
150
" lwi %0, %1, 4;" \
151
"2: swi %0, %2, 4;" \
152
" addk %0, r0, r0;" \
153
"3: " \
154
__FIXUP_SECTION \
155
"4: brid 3b;" \
156
" addik %0, r0, %3;" \
157
".previous;" \
158
__EX_TABLE_SECTION \
159
".word 1b,4b,2b,4b;" \
160
".previous;" \
161
: "=&r"(__gu_err) \
162
: "r"(&__gu_val), "r"(__gu_ptr), "i"(-EFAULT) \
163
); \
164
})
165
166
/**
167
* put_user: - Write a simple value into user space.
168
* @x: Value to copy to user space.
169
* @ptr: Destination address, in user space.
170
*
171
* Context: User context only. This function may sleep if pagefaults are
172
* enabled.
173
*
174
* This macro copies a single simple value from kernel space to user
175
* space. It supports simple types like char and int, but not larger
176
* data types like structures or arrays.
177
*
178
* @ptr must have pointer-to-simple-variable type, and @x must be assignable
179
* to the result of dereferencing @ptr.
180
*
181
* Returns zero on success, or -EFAULT on error.
182
*/
183
#define put_user(x, ptr) \
184
__put_user_check((x), (ptr), sizeof(*(ptr)))
185
186
#define __put_user_check(x, ptr, size) \
187
({ \
188
typeof(*(ptr)) volatile __pu_val = x; \
189
typeof(*(ptr)) __user *__pu_addr = (ptr); \
190
int __pu_err = 0; \
191
\
192
if (access_ok(__pu_addr, size)) { \
193
switch (size) { \
194
case 1: \
195
__put_user_asm("sb", __pu_addr, __pu_val, \
196
__pu_err); \
197
break; \
198
case 2: \
199
__put_user_asm("sh", __pu_addr, __pu_val, \
200
__pu_err); \
201
break; \
202
case 4: \
203
__put_user_asm("sw", __pu_addr, __pu_val, \
204
__pu_err); \
205
break; \
206
case 8: \
207
__put_user_asm_8(__pu_addr, __pu_val, __pu_err);\
208
break; \
209
default: \
210
__pu_err = __user_bad(); \
211
break; \
212
} \
213
} else { \
214
__pu_err = -EFAULT; \
215
} \
216
__pu_err; \
217
})
218
219
#define __put_user(x, ptr) \
220
({ \
221
__typeof__(*(ptr)) volatile __gu_val = (x); \
222
long __gu_err = 0; \
223
switch (sizeof(__gu_val)) { \
224
case 1: \
225
__put_user_asm("sb", (ptr), __gu_val, __gu_err); \
226
break; \
227
case 2: \
228
__put_user_asm("sh", (ptr), __gu_val, __gu_err); \
229
break; \
230
case 4: \
231
__put_user_asm("sw", (ptr), __gu_val, __gu_err); \
232
break; \
233
case 8: \
234
__put_user_asm_8((ptr), __gu_val, __gu_err); \
235
break; \
236
default: \
237
/*__gu_err = -EINVAL;*/ __gu_err = __user_bad(); \
238
} \
239
__gu_err; \
240
})
241
242
static inline unsigned long
243
raw_copy_from_user(void *to, const void __user *from, unsigned long n)
244
{
245
return __copy_tofrom_user((__force void __user *)to, from, n);
246
}
247
248
static inline unsigned long
249
raw_copy_to_user(void __user *to, const void *from, unsigned long n)
250
{
251
return __copy_tofrom_user(to, (__force const void __user *)from, n);
252
}
253
#define INLINE_COPY_FROM_USER
254
#define INLINE_COPY_TO_USER
255
256
/*
257
* Copy a null terminated string from userspace.
258
*/
259
__must_check long strncpy_from_user(char *dst, const char __user *src,
260
long count);
261
262
/*
263
* Return the size of a string (including the ending 0)
264
*
265
* Return 0 on exception, a value greater than N if too long
266
*/
267
__must_check long strnlen_user(const char __user *sstr, long len);
268
269
#endif /* _ASM_MICROBLAZE_UACCESS_H */
270
271