Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/m32r/lib/usercopy.c
10817 views
1
/*
2
* User address space access functions.
3
* The non inlined parts of asm-m32r/uaccess.h are here.
4
*
5
* Copyright 1997 Andi Kleen <[email protected]>
6
* Copyright 1997 Linus Torvalds
7
* Copyright 2001, 2002, 2004 Hirokazu Takata
8
*/
9
#include <linux/prefetch.h>
10
#include <linux/string.h>
11
#include <linux/thread_info.h>
12
#include <asm/uaccess.h>
13
14
unsigned long
15
__generic_copy_to_user(void __user *to, const void *from, unsigned long n)
16
{
17
prefetch(from);
18
if (access_ok(VERIFY_WRITE, to, n))
19
__copy_user(to,from,n);
20
return n;
21
}
22
23
unsigned long
24
__generic_copy_from_user(void *to, const void __user *from, unsigned long n)
25
{
26
prefetchw(to);
27
if (access_ok(VERIFY_READ, from, n))
28
__copy_user_zeroing(to,from,n);
29
else
30
memset(to, 0, n);
31
return n;
32
}
33
34
35
/*
36
* Copy a null terminated string from userspace.
37
*/
38
39
#ifdef CONFIG_ISA_DUAL_ISSUE
40
41
#define __do_strncpy_from_user(dst,src,count,res) \
42
do { \
43
int __d0, __d1, __d2; \
44
__asm__ __volatile__( \
45
" beqz %1, 2f\n" \
46
" .fillinsn\n" \
47
"0: ldb r14, @%3 || addi %3, #1\n" \
48
" stb r14, @%4 || addi %4, #1\n" \
49
" beqz r14, 1f\n" \
50
" addi %1, #-1\n" \
51
" bnez %1, 0b\n" \
52
" .fillinsn\n" \
53
"1: sub %0, %1\n" \
54
" .fillinsn\n" \
55
"2:\n" \
56
".section .fixup,\"ax\"\n" \
57
" .balign 4\n" \
58
"3: seth r14, #high(2b)\n" \
59
" or3 r14, r14, #low(2b)\n" \
60
" jmp r14 || ldi %0, #%5\n" \
61
".previous\n" \
62
".section __ex_table,\"a\"\n" \
63
" .balign 4\n" \
64
" .long 0b,3b\n" \
65
".previous" \
66
: "=&r"(res), "=&r"(count), "=&r" (__d0), "=&r" (__d1), \
67
"=&r" (__d2) \
68
: "i"(-EFAULT), "0"(count), "1"(count), "3"(src), \
69
"4"(dst) \
70
: "r14", "cbit", "memory"); \
71
} while (0)
72
73
#else /* not CONFIG_ISA_DUAL_ISSUE */
74
75
#define __do_strncpy_from_user(dst,src,count,res) \
76
do { \
77
int __d0, __d1, __d2; \
78
__asm__ __volatile__( \
79
" beqz %1, 2f\n" \
80
" .fillinsn\n" \
81
"0: ldb r14, @%3\n" \
82
" stb r14, @%4\n" \
83
" addi %3, #1\n" \
84
" addi %4, #1\n" \
85
" beqz r14, 1f\n" \
86
" addi %1, #-1\n" \
87
" bnez %1, 0b\n" \
88
" .fillinsn\n" \
89
"1: sub %0, %1\n" \
90
" .fillinsn\n" \
91
"2:\n" \
92
".section .fixup,\"ax\"\n" \
93
" .balign 4\n" \
94
"3: ldi %0, #%5\n" \
95
" seth r14, #high(2b)\n" \
96
" or3 r14, r14, #low(2b)\n" \
97
" jmp r14\n" \
98
".previous\n" \
99
".section __ex_table,\"a\"\n" \
100
" .balign 4\n" \
101
" .long 0b,3b\n" \
102
".previous" \
103
: "=&r"(res), "=&r"(count), "=&r" (__d0), "=&r" (__d1), \
104
"=&r" (__d2) \
105
: "i"(-EFAULT), "0"(count), "1"(count), "3"(src), \
106
"4"(dst) \
107
: "r14", "cbit", "memory"); \
108
} while (0)
109
110
#endif /* CONFIG_ISA_DUAL_ISSUE */
111
112
long
113
__strncpy_from_user(char *dst, const char __user *src, long count)
114
{
115
long res;
116
__do_strncpy_from_user(dst, src, count, res);
117
return res;
118
}
119
120
long
121
strncpy_from_user(char *dst, const char __user *src, long count)
122
{
123
long res = -EFAULT;
124
if (access_ok(VERIFY_READ, src, 1))
125
__do_strncpy_from_user(dst, src, count, res);
126
return res;
127
}
128
129
130
/*
131
* Zero Userspace
132
*/
133
134
#ifdef CONFIG_ISA_DUAL_ISSUE
135
136
#define __do_clear_user(addr,size) \
137
do { \
138
int __dst, __c; \
139
__asm__ __volatile__( \
140
" beqz %1, 9f\n" \
141
" and3 r14, %0, #3\n" \
142
" bnez r14, 2f\n" \
143
" and3 r14, %1, #3\n" \
144
" bnez r14, 2f\n" \
145
" and3 %1, %1, #3\n" \
146
" beqz %2, 2f\n" \
147
" addi %0, #-4\n" \
148
" .fillinsn\n" \
149
"0: ; word clear \n" \
150
" st %6, @+%0 || addi %2, #-1\n" \
151
" bnez %2, 0b\n" \
152
" beqz %1, 9f\n" \
153
" .fillinsn\n" \
154
"2: ; byte clear \n" \
155
" stb %6, @%0 || addi %1, #-1\n" \
156
" addi %0, #1\n" \
157
" bnez %1, 2b\n" \
158
" .fillinsn\n" \
159
"9:\n" \
160
".section .fixup,\"ax\"\n" \
161
" .balign 4\n" \
162
"4: slli %2, #2\n" \
163
" seth r14, #high(9b)\n" \
164
" or3 r14, r14, #low(9b)\n" \
165
" jmp r14 || add %1, %2\n" \
166
".previous\n" \
167
".section __ex_table,\"a\"\n" \
168
" .balign 4\n" \
169
" .long 0b,4b\n" \
170
" .long 2b,9b\n" \
171
".previous\n" \
172
: "=&r"(__dst), "=&r"(size), "=&r"(__c) \
173
: "0"(addr), "1"(size), "2"(size / 4), "r"(0) \
174
: "r14", "cbit", "memory"); \
175
} while (0)
176
177
#else /* not CONFIG_ISA_DUAL_ISSUE */
178
179
#define __do_clear_user(addr,size) \
180
do { \
181
int __dst, __c; \
182
__asm__ __volatile__( \
183
" beqz %1, 9f\n" \
184
" and3 r14, %0, #3\n" \
185
" bnez r14, 2f\n" \
186
" and3 r14, %1, #3\n" \
187
" bnez r14, 2f\n" \
188
" and3 %1, %1, #3\n" \
189
" beqz %2, 2f\n" \
190
" addi %0, #-4\n" \
191
" .fillinsn\n" \
192
"0: st %6, @+%0 ; word clear \n" \
193
" addi %2, #-1\n" \
194
" bnez %2, 0b\n" \
195
" beqz %1, 9f\n" \
196
" .fillinsn\n" \
197
"2: stb %6, @%0 ; byte clear \n" \
198
" addi %1, #-1\n" \
199
" addi %0, #1\n" \
200
" bnez %1, 2b\n" \
201
" .fillinsn\n" \
202
"9:\n" \
203
".section .fixup,\"ax\"\n" \
204
" .balign 4\n" \
205
"4: slli %2, #2\n" \
206
" add %1, %2\n" \
207
" seth r14, #high(9b)\n" \
208
" or3 r14, r14, #low(9b)\n" \
209
" jmp r14\n" \
210
".previous\n" \
211
".section __ex_table,\"a\"\n" \
212
" .balign 4\n" \
213
" .long 0b,4b\n" \
214
" .long 2b,9b\n" \
215
".previous\n" \
216
: "=&r"(__dst), "=&r"(size), "=&r"(__c) \
217
: "0"(addr), "1"(size), "2"(size / 4), "r"(0) \
218
: "r14", "cbit", "memory"); \
219
} while (0)
220
221
#endif /* not CONFIG_ISA_DUAL_ISSUE */
222
223
unsigned long
224
clear_user(void __user *to, unsigned long n)
225
{
226
if (access_ok(VERIFY_WRITE, to, n))
227
__do_clear_user(to, n);
228
return n;
229
}
230
231
unsigned long
232
__clear_user(void __user *to, unsigned long n)
233
{
234
__do_clear_user(to, n);
235
return n;
236
}
237
238
/*
239
* Return the size of a string (including the ending 0)
240
*
241
* Return 0 on exception, a value greater than N if too long
242
*/
243
244
#ifdef CONFIG_ISA_DUAL_ISSUE
245
246
long strnlen_user(const char __user *s, long n)
247
{
248
unsigned long mask = -__addr_ok(s);
249
unsigned long res;
250
251
__asm__ __volatile__(
252
" and %0, %5 || mv r1, %1\n"
253
" beqz %0, strnlen_exit\n"
254
" and3 r0, %1, #3\n"
255
" bnez r0, strnlen_byte_loop\n"
256
" cmpui %0, #4\n"
257
" bc strnlen_byte_loop\n"
258
"strnlen_word_loop:\n"
259
"0: ld r0, @%1+\n"
260
" pcmpbz r0\n"
261
" bc strnlen_last_bytes_fixup\n"
262
" addi %0, #-4\n"
263
" beqz %0, strnlen_exit\n"
264
" bgtz %0, strnlen_word_loop\n"
265
"strnlen_last_bytes:\n"
266
" mv %0, %4\n"
267
"strnlen_last_bytes_fixup:\n"
268
" addi %1, #-4\n"
269
"strnlen_byte_loop:\n"
270
"1: ldb r0, @%1 || addi %0, #-1\n"
271
" beqz r0, strnlen_exit\n"
272
" addi %1, #1\n"
273
" bnez %0, strnlen_byte_loop\n"
274
"strnlen_exit:\n"
275
" sub %1, r1\n"
276
" add3 %0, %1, #1\n"
277
" .fillinsn\n"
278
"9:\n"
279
".section .fixup,\"ax\"\n"
280
" .balign 4\n"
281
"4: addi %1, #-4\n"
282
" .fillinsn\n"
283
"5: seth r1, #high(9b)\n"
284
" or3 r1, r1, #low(9b)\n"
285
" jmp r1 || ldi %0, #0\n"
286
".previous\n"
287
".section __ex_table,\"a\"\n"
288
" .balign 4\n"
289
" .long 0b,4b\n"
290
" .long 1b,5b\n"
291
".previous"
292
: "=&r" (res), "=r" (s)
293
: "0" (n), "1" (s), "r" (n & 3), "r" (mask), "r"(0x01010101)
294
: "r0", "r1", "cbit");
295
296
/* NOTE: strnlen_user() algorithm:
297
* {
298
* char *p;
299
* for (p = s; n-- && *p != '\0'; ++p)
300
* ;
301
* return p - s + 1;
302
* }
303
*/
304
305
/* NOTE: If a null char. exists, return 0.
306
* if ((x - 0x01010101) & ~x & 0x80808080)\n"
307
* return 0;\n"
308
*/
309
310
return res & mask;
311
}
312
313
#else /* not CONFIG_ISA_DUAL_ISSUE */
314
315
long strnlen_user(const char __user *s, long n)
316
{
317
unsigned long mask = -__addr_ok(s);
318
unsigned long res;
319
320
__asm__ __volatile__(
321
" and %0, %5\n"
322
" mv r1, %1\n"
323
" beqz %0, strnlen_exit\n"
324
" and3 r0, %1, #3\n"
325
" bnez r0, strnlen_byte_loop\n"
326
" cmpui %0, #4\n"
327
" bc strnlen_byte_loop\n"
328
" sll3 r3, %6, #7\n"
329
"strnlen_word_loop:\n"
330
"0: ld r0, @%1+\n"
331
" not r2, r0\n"
332
" sub r0, %6\n"
333
" and r2, r3\n"
334
" and r2, r0\n"
335
" bnez r2, strnlen_last_bytes_fixup\n"
336
" addi %0, #-4\n"
337
" beqz %0, strnlen_exit\n"
338
" bgtz %0, strnlen_word_loop\n"
339
"strnlen_last_bytes:\n"
340
" mv %0, %4\n"
341
"strnlen_last_bytes_fixup:\n"
342
" addi %1, #-4\n"
343
"strnlen_byte_loop:\n"
344
"1: ldb r0, @%1\n"
345
" addi %0, #-1\n"
346
" beqz r0, strnlen_exit\n"
347
" addi %1, #1\n"
348
" bnez %0, strnlen_byte_loop\n"
349
"strnlen_exit:\n"
350
" sub %1, r1\n"
351
" add3 %0, %1, #1\n"
352
" .fillinsn\n"
353
"9:\n"
354
".section .fixup,\"ax\"\n"
355
" .balign 4\n"
356
"4: addi %1, #-4\n"
357
" .fillinsn\n"
358
"5: ldi %0, #0\n"
359
" seth r1, #high(9b)\n"
360
" or3 r1, r1, #low(9b)\n"
361
" jmp r1\n"
362
".previous\n"
363
".section __ex_table,\"a\"\n"
364
" .balign 4\n"
365
" .long 0b,4b\n"
366
" .long 1b,5b\n"
367
".previous"
368
: "=&r" (res), "=r" (s)
369
: "0" (n), "1" (s), "r" (n & 3), "r" (mask), "r"(0x01010101)
370
: "r0", "r1", "r2", "r3", "cbit");
371
372
/* NOTE: strnlen_user() algorithm:
373
* {
374
* char *p;
375
* for (p = s; n-- && *p != '\0'; ++p)
376
* ;
377
* return p - s + 1;
378
* }
379
*/
380
381
/* NOTE: If a null char. exists, return 0.
382
* if ((x - 0x01010101) & ~x & 0x80808080)\n"
383
* return 0;\n"
384
*/
385
386
return res & mask;
387
}
388
389
#endif /* CONFIG_ISA_DUAL_ISSUE */
390
391
392