blob: 024840266ba0d94144697de13194417d0427d22f [file] [log] [blame]
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +02001/*
2 * Copyright 2008 Vitaly Mayatskikh <vmayatsk@redhat.com>
3 * Copyright 2002 Andi Kleen, SuSE Labs.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * Subject to the GNU Public License v2.
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +02005 *
6 * Functions to copy from and to user space.
7 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07008
Jan Beulich8d379da2006-09-26 10:52:32 +02009#include <linux/linkage.h>
10#include <asm/dwarf2.h>
11
Andi Kleen7bcd3f32006-02-03 21:51:02 +010012#define FIX_ALIGNMENT 1
13
Andi Kleen3022d732006-09-26 10:52:39 +020014#include <asm/current.h>
15#include <asm/asm-offsets.h>
16#include <asm/thread_info.h>
17#include <asm/cpufeature.h>
Fenghua Yu4307bec2011-05-17 15:29:15 -070018#include <asm/alternative-asm.h>
Andi Kleen3022d732006-09-26 10:52:39 +020019
Fenghua Yu4307bec2011-05-17 15:29:15 -070020/*
21 * By placing feature2 after feature1 in altinstructions section, we logically
22 * implement:
23 * If CPU has feature2, jmp to alt2 is used
24 * else if CPU has feature1, jmp to alt1 is used
25 * else jmp to orig is used.
26 */
27 .macro ALTERNATIVE_JUMP feature1,feature2,orig,alt1,alt2
Andi Kleen3022d732006-09-26 10:52:39 +0200280:
29 .byte 0xe9 /* 32bit jump */
30 .long \orig-1f /* by default jump to orig */
311:
32 .section .altinstr_replacement,"ax"
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200332: .byte 0xe9 /* near jump with 32bit immediate */
Fenghua Yu4307bec2011-05-17 15:29:15 -070034 .long \alt1-1b /* offset */ /* or alternatively to alt1 */
353: .byte 0xe9 /* near jump with 32bit immediate */
36 .long \alt2-1b /* offset */ /* or alternatively to alt2 */
Andi Kleen3022d732006-09-26 10:52:39 +020037 .previous
Fenghua Yu4307bec2011-05-17 15:29:15 -070038
Andi Kleen3022d732006-09-26 10:52:39 +020039 .section .altinstructions,"a"
Fenghua Yu4307bec2011-05-17 15:29:15 -070040 altinstruction_entry 0b,2b,\feature1,5,5
41 altinstruction_entry 0b,3b,\feature2,5,5
Andi Kleen3022d732006-09-26 10:52:39 +020042 .previous
43 .endm
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +020045 .macro ALIGN_DESTINATION
46#ifdef FIX_ALIGNMENT
47 /* check for bad alignment of destination */
48 movl %edi,%ecx
49 andl $7,%ecx
50 jz 102f /* already aligned */
51 subl $8,%ecx
52 negl %ecx
53 subl %ecx,%edx
54100: movb (%rsi),%al
55101: movb %al,(%rdi)
56 incq %rsi
57 incq %rdi
58 decl %ecx
59 jnz 100b
60102:
61 .section .fixup,"ax"
Vitaly Mayatskikhafd962a2008-07-30 13:30:14 +020062103: addl %ecx,%edx /* ecx is zerorest also */
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +020063 jmp copy_user_handle_tail
64 .previous
65
66 .section __ex_table,"a"
67 .align 8
68 .quad 100b,103b
69 .quad 101b,103b
70 .previous
71#endif
72 .endm
73
74/* Standard copy_to_user with segment limit checking */
Frederic Weisbecker3c93ca02009-11-16 15:42:18 +010075ENTRY(_copy_to_user)
Jan Beulich8d379da2006-09-26 10:52:32 +020076 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 GET_THREAD_INFO(%rax)
78 movq %rdi,%rcx
79 addq %rdx,%rcx
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +020080 jc bad_to_user
Glauber Costa26ccb8a2008-06-24 11:19:35 -030081 cmpq TI_addr_limit(%rax),%rcx
Jiri Olsa26afb7c2011-05-12 16:30:30 +020082 ja bad_to_user
Fenghua Yu4307bec2011-05-17 15:29:15 -070083 ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,X86_FEATURE_ERMS, \
84 copy_user_generic_unrolled,copy_user_generic_string, \
85 copy_user_enhanced_fast_string
Jan Beulich8d379da2006-09-26 10:52:32 +020086 CFI_ENDPROC
Frederic Weisbecker3c93ca02009-11-16 15:42:18 +010087ENDPROC(_copy_to_user)
Andi Kleen7bcd3f32006-02-03 21:51:02 +010088
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +020089/* Standard copy_from_user with segment limit checking */
Arjan van de Ven9f0cf4a2009-09-26 14:33:01 +020090ENTRY(_copy_from_user)
Jan Beulich8d379da2006-09-26 10:52:32 +020091 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 GET_THREAD_INFO(%rax)
93 movq %rsi,%rcx
94 addq %rdx,%rcx
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +020095 jc bad_from_user
Glauber Costa26ccb8a2008-06-24 11:19:35 -030096 cmpq TI_addr_limit(%rax),%rcx
Jiri Olsa26afb7c2011-05-12 16:30:30 +020097 ja bad_from_user
Fenghua Yu4307bec2011-05-17 15:29:15 -070098 ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,X86_FEATURE_ERMS, \
99 copy_user_generic_unrolled,copy_user_generic_string, \
100 copy_user_enhanced_fast_string
Jan Beulich8d379da2006-09-26 10:52:32 +0200101 CFI_ENDPROC
Arjan van de Ven9f0cf4a2009-09-26 14:33:01 +0200102ENDPROC(_copy_from_user)
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200103
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 .section .fixup,"ax"
105 /* must zero dest */
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200106ENTRY(bad_from_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107bad_from_user:
Jan Beulich8d379da2006-09-26 10:52:32 +0200108 CFI_STARTPROC
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 movl %edx,%ecx
110 xorl %eax,%eax
111 rep
112 stosb
113bad_to_user:
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200114 movl %edx,%eax
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 ret
Jan Beulich8d379da2006-09-26 10:52:32 +0200116 CFI_ENDPROC
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200117ENDPROC(bad_from_user)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 .previous
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200119
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120/*
Andi Kleen3022d732006-09-26 10:52:39 +0200121 * copy_user_generic_unrolled - memory copy with exception handling.
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200122 * This version is for CPUs like P4 that don't have efficient micro
123 * code for rep movsq
124 *
125 * Input:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 * rdi destination
127 * rsi source
128 * rdx count
129 *
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200130 * Output:
Lucas De Marchi0d2eb442011-03-17 16:24:16 -0300131 * eax uncopied bytes or 0 if successful.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 */
Andi Kleen3022d732006-09-26 10:52:39 +0200133ENTRY(copy_user_generic_unrolled)
Jan Beulich8d379da2006-09-26 10:52:32 +0200134 CFI_STARTPROC
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200135 cmpl $8,%edx
136 jb 20f /* less then 8 bytes, go to byte copy loop */
137 ALIGN_DESTINATION
138 movl %edx,%ecx
139 andl $63,%edx
140 shrl $6,%ecx
141 jz 17f
1421: movq (%rsi),%r8
1432: movq 1*8(%rsi),%r9
1443: movq 2*8(%rsi),%r10
1454: movq 3*8(%rsi),%r11
1465: movq %r8,(%rdi)
1476: movq %r9,1*8(%rdi)
1487: movq %r10,2*8(%rdi)
1498: movq %r11,3*8(%rdi)
1509: movq 4*8(%rsi),%r8
15110: movq 5*8(%rsi),%r9
15211: movq 6*8(%rsi),%r10
15312: movq 7*8(%rsi),%r11
15413: movq %r8,4*8(%rdi)
15514: movq %r9,5*8(%rdi)
15615: movq %r10,6*8(%rdi)
15716: movq %r11,7*8(%rdi)
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100158 leaq 64(%rsi),%rsi
159 leaq 64(%rdi),%rdi
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200160 decl %ecx
161 jnz 1b
16217: movl %edx,%ecx
163 andl $7,%edx
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100164 shrl $3,%ecx
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200165 jz 20f
16618: movq (%rsi),%r8
16719: movq %r8,(%rdi)
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100168 leaq 8(%rsi),%rsi
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200169 leaq 8(%rdi),%rdi
170 decl %ecx
171 jnz 18b
17220: andl %edx,%edx
173 jz 23f
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100174 movl %edx,%ecx
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +020017521: movb (%rsi),%al
17622: movb %al,(%rdi)
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100177 incq %rsi
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200178 incq %rdi
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100179 decl %ecx
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200180 jnz 21b
18123: xor %eax,%eax
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100182 ret
183
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200184 .section .fixup,"ax"
18530: shll $6,%ecx
186 addl %ecx,%edx
187 jmp 60f
Jeremy Fitzhardinge27cb0a72008-07-10 12:52:52 -070018840: lea (%rdx,%rcx,8),%rdx
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200189 jmp 60f
19050: movl %ecx,%edx
19160: jmp copy_user_handle_tail /* ecx is zerorest also */
192 .previous
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100193
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100194 .section __ex_table,"a"
195 .align 8
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200196 .quad 1b,30b
197 .quad 2b,30b
198 .quad 3b,30b
199 .quad 4b,30b
200 .quad 5b,30b
201 .quad 6b,30b
202 .quad 7b,30b
203 .quad 8b,30b
204 .quad 9b,30b
205 .quad 10b,30b
206 .quad 11b,30b
207 .quad 12b,30b
208 .quad 13b,30b
209 .quad 14b,30b
210 .quad 15b,30b
211 .quad 16b,30b
212 .quad 18b,40b
213 .quad 19b,40b
214 .quad 21b,50b
215 .quad 22b,50b
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100216 .previous
Jan Beulich8d379da2006-09-26 10:52:32 +0200217 CFI_ENDPROC
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200218ENDPROC(copy_user_generic_unrolled)
Jan Beulich8d379da2006-09-26 10:52:32 +0200219
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200220/* Some CPUs run faster using the string copy instructions.
221 * This is also a lot simpler. Use them when possible.
222 *
223 * Only 4GB of copy is supported. This shouldn't be a problem
224 * because the kernel normally only writes from/to page sized chunks
225 * even if user space passed a longer buffer.
226 * And more would be dangerous because both Intel and AMD have
227 * errata with rep movsq > 4GB. If someone feels the need to fix
228 * this please consider this.
229 *
230 * Input:
231 * rdi destination
232 * rsi source
233 * rdx count
234 *
235 * Output:
236 * eax uncopied bytes or 0 if successful.
237 */
Andi Kleen3022d732006-09-26 10:52:39 +0200238ENTRY(copy_user_generic_string)
Jan Beulich8d379da2006-09-26 10:52:32 +0200239 CFI_STARTPROC
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200240 andl %edx,%edx
241 jz 4f
242 cmpl $8,%edx
243 jb 2f /* less than 8 bytes, go to byte copy loop */
244 ALIGN_DESTINATION
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 movl %edx,%ecx
246 shrl $3,%ecx
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200247 andl $7,%edx
2481: rep
Andi Kleen3022d732006-09-26 10:52:39 +0200249 movsq
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +02002502: movl %edx,%ecx
2513: rep
252 movsb
2534: xorl %eax,%eax
Andi Kleen7bcd3f32006-02-03 21:51:02 +0100254 ret
Andi Kleen3022d732006-09-26 10:52:39 +0200255
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200256 .section .fixup,"ax"
Jeremy Fitzhardinge27cb0a72008-07-10 12:52:52 -070025711: lea (%rdx,%rcx,8),%rcx
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +020025812: movl %ecx,%edx /* ecx is zerorest also */
259 jmp copy_user_handle_tail
260 .previous
Andi Kleen2cbc9ee2006-01-11 22:44:45 +0100261
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 .section __ex_table,"a"
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200263 .align 8
264 .quad 1b,11b
265 .quad 3b,12b
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 .previous
Vitaly Mayatskikhad2fc2c2008-07-02 15:53:13 +0200267 CFI_ENDPROC
268ENDPROC(copy_user_generic_string)
Fenghua Yu4307bec2011-05-17 15:29:15 -0700269
270/*
271 * Some CPUs are adding enhanced REP MOVSB/STOSB instructions.
272 * It's recommended to use enhanced REP MOVSB/STOSB if it's enabled.
273 *
274 * Input:
275 * rdi destination
276 * rsi source
277 * rdx count
278 *
279 * Output:
280 * eax uncopied bytes or 0 if successful.
281 */
282ENTRY(copy_user_enhanced_fast_string)
283 CFI_STARTPROC
284 andl %edx,%edx
285 jz 2f
286 movl %edx,%ecx
2871: rep
288 movsb
2892: xorl %eax,%eax
290 ret
291
292 .section .fixup,"ax"
29312: movl %ecx,%edx /* ecx is zerorest also */
294 jmp copy_user_handle_tail
295 .previous
296
297 .section __ex_table,"a"
298 .align 8
299 .quad 1b,12b
300 .previous
301 CFI_ENDPROC
302ENDPROC(copy_user_enhanced_fast_string)