Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/lib/usercopy_32.c
26444 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* User address space access functions.
4
* The non inlined parts of asm-i386/uaccess.h are here.
5
*
6
* Copyright 1997 Andi Kleen <[email protected]>
7
* Copyright 1997 Linus Torvalds
8
*/
9
#include <linux/export.h>
10
#include <linux/uaccess.h>
11
#include <asm/asm.h>
12
13
#ifdef CONFIG_X86_INTEL_USERCOPY
14
/*
15
* Alignment at which movsl is preferred for bulk memory copies.
16
*/
17
struct movsl_mask movsl_mask __read_mostly;
18
#endif
19
20
static inline int __movsl_is_ok(unsigned long a1, unsigned long a2, unsigned long n)
21
{
22
#ifdef CONFIG_X86_INTEL_USERCOPY
23
if (n >= 64 && ((a1 ^ a2) & movsl_mask.mask))
24
return 0;
25
#endif
26
return 1;
27
}
28
#define movsl_is_ok(a1, a2, n) \
29
__movsl_is_ok((unsigned long)(a1), (unsigned long)(a2), (n))
30
31
/*
32
* Zero Userspace
33
*/
34
35
#define __do_clear_user(addr,size) \
36
do { \
37
int __d0; \
38
might_fault(); \
39
__asm__ __volatile__( \
40
ASM_STAC "\n" \
41
"0: rep stosl\n" \
42
" movl %2,%0\n" \
43
"1: rep stosb\n" \
44
"2: " ASM_CLAC "\n" \
45
_ASM_EXTABLE_TYPE_REG(0b, 2b, EX_TYPE_UCOPY_LEN4, %2) \
46
_ASM_EXTABLE_UA(1b, 2b) \
47
: "=&c"(size), "=&D" (__d0) \
48
: "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0)); \
49
} while (0)
50
51
/**
52
* clear_user - Zero a block of memory in user space.
53
* @to: Destination address, in user space.
54
* @n: Number of bytes to zero.
55
*
56
* Zero a block of memory in user space.
57
*
58
* Return: number of bytes that could not be cleared.
59
* On success, this will be zero.
60
*/
61
unsigned long
62
clear_user(void __user *to, unsigned long n)
63
{
64
might_fault();
65
if (access_ok(to, n))
66
__do_clear_user(to, n);
67
return n;
68
}
69
EXPORT_SYMBOL(clear_user);
70
71
/**
72
* __clear_user - Zero a block of memory in user space, with less checking.
73
* @to: Destination address, in user space.
74
* @n: Number of bytes to zero.
75
*
76
* Zero a block of memory in user space. Caller must check
77
* the specified block with access_ok() before calling this function.
78
*
79
* Return: number of bytes that could not be cleared.
80
* On success, this will be zero.
81
*/
82
unsigned long
83
__clear_user(void __user *to, unsigned long n)
84
{
85
__do_clear_user(to, n);
86
return n;
87
}
88
EXPORT_SYMBOL(__clear_user);
89
90
#ifdef CONFIG_X86_INTEL_USERCOPY
91
static unsigned long
92
__copy_user_intel(void __user *to, const void *from, unsigned long size)
93
{
94
int d0, d1;
95
__asm__ __volatile__(
96
" .align 2,0x90\n"
97
"1: movl 32(%4), %%eax\n"
98
" cmpl $67, %0\n"
99
" jbe 3f\n"
100
"2: movl 64(%4), %%eax\n"
101
" .align 2,0x90\n"
102
"3: movl 0(%4), %%eax\n"
103
"4: movl 4(%4), %%edx\n"
104
"5: movl %%eax, 0(%3)\n"
105
"6: movl %%edx, 4(%3)\n"
106
"7: movl 8(%4), %%eax\n"
107
"8: movl 12(%4),%%edx\n"
108
"9: movl %%eax, 8(%3)\n"
109
"10: movl %%edx, 12(%3)\n"
110
"11: movl 16(%4), %%eax\n"
111
"12: movl 20(%4), %%edx\n"
112
"13: movl %%eax, 16(%3)\n"
113
"14: movl %%edx, 20(%3)\n"
114
"15: movl 24(%4), %%eax\n"
115
"16: movl 28(%4), %%edx\n"
116
"17: movl %%eax, 24(%3)\n"
117
"18: movl %%edx, 28(%3)\n"
118
"19: movl 32(%4), %%eax\n"
119
"20: movl 36(%4), %%edx\n"
120
"21: movl %%eax, 32(%3)\n"
121
"22: movl %%edx, 36(%3)\n"
122
"23: movl 40(%4), %%eax\n"
123
"24: movl 44(%4), %%edx\n"
124
"25: movl %%eax, 40(%3)\n"
125
"26: movl %%edx, 44(%3)\n"
126
"27: movl 48(%4), %%eax\n"
127
"28: movl 52(%4), %%edx\n"
128
"29: movl %%eax, 48(%3)\n"
129
"30: movl %%edx, 52(%3)\n"
130
"31: movl 56(%4), %%eax\n"
131
"32: movl 60(%4), %%edx\n"
132
"33: movl %%eax, 56(%3)\n"
133
"34: movl %%edx, 60(%3)\n"
134
" addl $-64, %0\n"
135
" addl $64, %4\n"
136
" addl $64, %3\n"
137
" cmpl $63, %0\n"
138
" ja 1b\n"
139
"35: movl %0, %%eax\n"
140
" shrl $2, %0\n"
141
" andl $3, %%eax\n"
142
" cld\n"
143
"99: rep movsl\n"
144
"36: movl %%eax, %0\n"
145
"37: rep movsb\n"
146
"100:\n"
147
_ASM_EXTABLE_UA(1b, 100b)
148
_ASM_EXTABLE_UA(2b, 100b)
149
_ASM_EXTABLE_UA(3b, 100b)
150
_ASM_EXTABLE_UA(4b, 100b)
151
_ASM_EXTABLE_UA(5b, 100b)
152
_ASM_EXTABLE_UA(6b, 100b)
153
_ASM_EXTABLE_UA(7b, 100b)
154
_ASM_EXTABLE_UA(8b, 100b)
155
_ASM_EXTABLE_UA(9b, 100b)
156
_ASM_EXTABLE_UA(10b, 100b)
157
_ASM_EXTABLE_UA(11b, 100b)
158
_ASM_EXTABLE_UA(12b, 100b)
159
_ASM_EXTABLE_UA(13b, 100b)
160
_ASM_EXTABLE_UA(14b, 100b)
161
_ASM_EXTABLE_UA(15b, 100b)
162
_ASM_EXTABLE_UA(16b, 100b)
163
_ASM_EXTABLE_UA(17b, 100b)
164
_ASM_EXTABLE_UA(18b, 100b)
165
_ASM_EXTABLE_UA(19b, 100b)
166
_ASM_EXTABLE_UA(20b, 100b)
167
_ASM_EXTABLE_UA(21b, 100b)
168
_ASM_EXTABLE_UA(22b, 100b)
169
_ASM_EXTABLE_UA(23b, 100b)
170
_ASM_EXTABLE_UA(24b, 100b)
171
_ASM_EXTABLE_UA(25b, 100b)
172
_ASM_EXTABLE_UA(26b, 100b)
173
_ASM_EXTABLE_UA(27b, 100b)
174
_ASM_EXTABLE_UA(28b, 100b)
175
_ASM_EXTABLE_UA(29b, 100b)
176
_ASM_EXTABLE_UA(30b, 100b)
177
_ASM_EXTABLE_UA(31b, 100b)
178
_ASM_EXTABLE_UA(32b, 100b)
179
_ASM_EXTABLE_UA(33b, 100b)
180
_ASM_EXTABLE_UA(34b, 100b)
181
_ASM_EXTABLE_UA(35b, 100b)
182
_ASM_EXTABLE_UA(36b, 100b)
183
_ASM_EXTABLE_UA(37b, 100b)
184
_ASM_EXTABLE_TYPE_REG(99b, 100b, EX_TYPE_UCOPY_LEN4, %%eax)
185
: "=&c"(size), "=&D" (d0), "=&S" (d1)
186
: "1"(to), "2"(from), "0"(size)
187
: "eax", "edx", "memory");
188
return size;
189
}
190
191
static unsigned long __copy_user_intel_nocache(void *to,
192
const void __user *from, unsigned long size)
193
{
194
int d0, d1;
195
196
__asm__ __volatile__(
197
" .align 2,0x90\n"
198
"0: movl 32(%4), %%eax\n"
199
" cmpl $67, %0\n"
200
" jbe 2f\n"
201
"1: movl 64(%4), %%eax\n"
202
" .align 2,0x90\n"
203
"2: movl 0(%4), %%eax\n"
204
"21: movl 4(%4), %%edx\n"
205
" movnti %%eax, 0(%3)\n"
206
" movnti %%edx, 4(%3)\n"
207
"3: movl 8(%4), %%eax\n"
208
"31: movl 12(%4),%%edx\n"
209
" movnti %%eax, 8(%3)\n"
210
" movnti %%edx, 12(%3)\n"
211
"4: movl 16(%4), %%eax\n"
212
"41: movl 20(%4), %%edx\n"
213
" movnti %%eax, 16(%3)\n"
214
" movnti %%edx, 20(%3)\n"
215
"10: movl 24(%4), %%eax\n"
216
"51: movl 28(%4), %%edx\n"
217
" movnti %%eax, 24(%3)\n"
218
" movnti %%edx, 28(%3)\n"
219
"11: movl 32(%4), %%eax\n"
220
"61: movl 36(%4), %%edx\n"
221
" movnti %%eax, 32(%3)\n"
222
" movnti %%edx, 36(%3)\n"
223
"12: movl 40(%4), %%eax\n"
224
"71: movl 44(%4), %%edx\n"
225
" movnti %%eax, 40(%3)\n"
226
" movnti %%edx, 44(%3)\n"
227
"13: movl 48(%4), %%eax\n"
228
"81: movl 52(%4), %%edx\n"
229
" movnti %%eax, 48(%3)\n"
230
" movnti %%edx, 52(%3)\n"
231
"14: movl 56(%4), %%eax\n"
232
"91: movl 60(%4), %%edx\n"
233
" movnti %%eax, 56(%3)\n"
234
" movnti %%edx, 60(%3)\n"
235
" addl $-64, %0\n"
236
" addl $64, %4\n"
237
" addl $64, %3\n"
238
" cmpl $63, %0\n"
239
" ja 0b\n"
240
" sfence \n"
241
"5: movl %0, %%eax\n"
242
" shrl $2, %0\n"
243
" andl $3, %%eax\n"
244
" cld\n"
245
"6: rep movsl\n"
246
" movl %%eax,%0\n"
247
"7: rep movsb\n"
248
"8:\n"
249
_ASM_EXTABLE_UA(0b, 8b)
250
_ASM_EXTABLE_UA(1b, 8b)
251
_ASM_EXTABLE_UA(2b, 8b)
252
_ASM_EXTABLE_UA(21b, 8b)
253
_ASM_EXTABLE_UA(3b, 8b)
254
_ASM_EXTABLE_UA(31b, 8b)
255
_ASM_EXTABLE_UA(4b, 8b)
256
_ASM_EXTABLE_UA(41b, 8b)
257
_ASM_EXTABLE_UA(10b, 8b)
258
_ASM_EXTABLE_UA(51b, 8b)
259
_ASM_EXTABLE_UA(11b, 8b)
260
_ASM_EXTABLE_UA(61b, 8b)
261
_ASM_EXTABLE_UA(12b, 8b)
262
_ASM_EXTABLE_UA(71b, 8b)
263
_ASM_EXTABLE_UA(13b, 8b)
264
_ASM_EXTABLE_UA(81b, 8b)
265
_ASM_EXTABLE_UA(14b, 8b)
266
_ASM_EXTABLE_UA(91b, 8b)
267
_ASM_EXTABLE_TYPE_REG(6b, 8b, EX_TYPE_UCOPY_LEN4, %%eax)
268
_ASM_EXTABLE_UA(7b, 8b)
269
: "=&c"(size), "=&D" (d0), "=&S" (d1)
270
: "1"(to), "2"(from), "0"(size)
271
: "eax", "edx", "memory");
272
return size;
273
}
274
275
#else
276
277
/*
278
* Leave these declared but undefined. They should not be any references to
279
* them
280
*/
281
unsigned long __copy_user_intel(void __user *to, const void *from,
282
unsigned long size);
283
#endif /* CONFIG_X86_INTEL_USERCOPY */
284
285
/* Generic arbitrary sized copy. */
286
#define __copy_user(to, from, size) \
287
do { \
288
int __d0, __d1, __d2; \
289
__asm__ __volatile__( \
290
" cmp $7,%0\n" \
291
" jbe 1f\n" \
292
" movl %1,%0\n" \
293
" negl %0\n" \
294
" andl $7,%0\n" \
295
" subl %0,%3\n" \
296
"4: rep movsb\n" \
297
" movl %3,%0\n" \
298
" shrl $2,%0\n" \
299
" andl $3,%3\n" \
300
" .align 2,0x90\n" \
301
"0: rep movsl\n" \
302
" movl %3,%0\n" \
303
"1: rep movsb\n" \
304
"2:\n" \
305
_ASM_EXTABLE_TYPE_REG(4b, 2b, EX_TYPE_UCOPY_LEN1, %3) \
306
_ASM_EXTABLE_TYPE_REG(0b, 2b, EX_TYPE_UCOPY_LEN4, %3) \
307
_ASM_EXTABLE_UA(1b, 2b) \
308
: "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) \
309
: "3"(size), "0"(size), "1"(to), "2"(from) \
310
: "memory"); \
311
} while (0)
312
313
unsigned long __copy_user_ll(void *to, const void *from, unsigned long n)
314
{
315
__uaccess_begin_nospec();
316
if (movsl_is_ok(to, from, n))
317
__copy_user(to, from, n);
318
else
319
n = __copy_user_intel(to, from, n);
320
__uaccess_end();
321
return n;
322
}
323
EXPORT_SYMBOL(__copy_user_ll);
324
325
unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from,
326
unsigned long n)
327
{
328
__uaccess_begin_nospec();
329
#ifdef CONFIG_X86_INTEL_USERCOPY
330
if (n > 64 && static_cpu_has(X86_FEATURE_XMM2))
331
n = __copy_user_intel_nocache(to, from, n);
332
else
333
__copy_user(to, from, n);
334
#else
335
__copy_user(to, from, n);
336
#endif
337
__uaccess_end();
338
return n;
339
}
340
EXPORT_SYMBOL(__copy_from_user_ll_nocache_nozero);
341
342