x86/asm/uaccess: Unify the ALIGN_DESTINATION macro
[linux-2.6/btrfs-unstable.git] / arch / x86 / lib / copy_user_64.S
blob06ce685c3a5dacd8d99939662cc35dd783f0c36b
1 /*
2  * Copyright 2008 Vitaly Mayatskikh <vmayatsk@redhat.com>
3  * Copyright 2002 Andi Kleen, SuSE Labs.
4  * Subject to the GNU Public License v2.
5  *
6  * Functions to copy from and to user space.
7  */
9 #include <linux/linkage.h>
10 #include <asm/dwarf2.h>
11 #include <asm/current.h>
12 #include <asm/asm-offsets.h>
13 #include <asm/thread_info.h>
14 #include <asm/cpufeature.h>
15 #include <asm/alternative-asm.h>
16 #include <asm/asm.h>
17 #include <asm/smap.h>
19 /* Standard copy_to_user with segment limit checking */
20 ENTRY(_copy_to_user)
21         CFI_STARTPROC
22         GET_THREAD_INFO(%rax)
23         movq %rdi,%rcx
24         addq %rdx,%rcx
25         jc bad_to_user
26         cmpq TI_addr_limit(%rax),%rcx
27         ja bad_to_user
28         ALTERNATIVE_2 "jmp copy_user_generic_unrolled",         \
29                       "jmp copy_user_generic_string",           \
30                       X86_FEATURE_REP_GOOD,                     \
31                       "jmp copy_user_enhanced_fast_string",     \
32                       X86_FEATURE_ERMS
33         CFI_ENDPROC
34 ENDPROC(_copy_to_user)
36 /* Standard copy_from_user with segment limit checking */
37 ENTRY(_copy_from_user)
38         CFI_STARTPROC
39         GET_THREAD_INFO(%rax)
40         movq %rsi,%rcx
41         addq %rdx,%rcx
42         jc bad_from_user
43         cmpq TI_addr_limit(%rax),%rcx
44         ja bad_from_user
45         ALTERNATIVE_2 "jmp copy_user_generic_unrolled",         \
46                       "jmp copy_user_generic_string",           \
47                       X86_FEATURE_REP_GOOD,                     \
48                       "jmp copy_user_enhanced_fast_string",     \
49                       X86_FEATURE_ERMS
50         CFI_ENDPROC
51 ENDPROC(_copy_from_user)
53         .section .fixup,"ax"
54         /* must zero dest */
55 ENTRY(bad_from_user)
56 bad_from_user:
57         CFI_STARTPROC
58         movl %edx,%ecx
59         xorl %eax,%eax
60         rep
61         stosb
62 bad_to_user:
63         movl %edx,%eax
64         ret
65         CFI_ENDPROC
66 ENDPROC(bad_from_user)
67         .previous
70  * copy_user_generic_unrolled - memory copy with exception handling.
71  * This version is for CPUs like P4 that don't have efficient micro
72  * code for rep movsq
73  *
74  * Input:
75  * rdi destination
76  * rsi source
77  * rdx count
78  *
79  * Output:
80  * eax uncopied bytes or 0 if successful.
81  */
82 ENTRY(copy_user_generic_unrolled)
83         CFI_STARTPROC
84         ASM_STAC
85         cmpl $8,%edx
86         jb 20f          /* less then 8 bytes, go to byte copy loop */
87         ALIGN_DESTINATION
88         movl %edx,%ecx
89         andl $63,%edx
90         shrl $6,%ecx
91         jz 17f
92 1:      movq (%rsi),%r8
93 2:      movq 1*8(%rsi),%r9
94 3:      movq 2*8(%rsi),%r10
95 4:      movq 3*8(%rsi),%r11
96 5:      movq %r8,(%rdi)
97 6:      movq %r9,1*8(%rdi)
98 7:      movq %r10,2*8(%rdi)
99 8:      movq %r11,3*8(%rdi)
100 9:      movq 4*8(%rsi),%r8
101 10:     movq 5*8(%rsi),%r9
102 11:     movq 6*8(%rsi),%r10
103 12:     movq 7*8(%rsi),%r11
104 13:     movq %r8,4*8(%rdi)
105 14:     movq %r9,5*8(%rdi)
106 15:     movq %r10,6*8(%rdi)
107 16:     movq %r11,7*8(%rdi)
108         leaq 64(%rsi),%rsi
109         leaq 64(%rdi),%rdi
110         decl %ecx
111         jnz 1b
112 17:     movl %edx,%ecx
113         andl $7,%edx
114         shrl $3,%ecx
115         jz 20f
116 18:     movq (%rsi),%r8
117 19:     movq %r8,(%rdi)
118         leaq 8(%rsi),%rsi
119         leaq 8(%rdi),%rdi
120         decl %ecx
121         jnz 18b
122 20:     andl %edx,%edx
123         jz 23f
124         movl %edx,%ecx
125 21:     movb (%rsi),%al
126 22:     movb %al,(%rdi)
127         incq %rsi
128         incq %rdi
129         decl %ecx
130         jnz 21b
131 23:     xor %eax,%eax
132         ASM_CLAC
133         ret
135         .section .fixup,"ax"
136 30:     shll $6,%ecx
137         addl %ecx,%edx
138         jmp 60f
139 40:     leal (%rdx,%rcx,8),%edx
140         jmp 60f
141 50:     movl %ecx,%edx
142 60:     jmp copy_user_handle_tail /* ecx is zerorest also */
143         .previous
145         _ASM_EXTABLE(1b,30b)
146         _ASM_EXTABLE(2b,30b)
147         _ASM_EXTABLE(3b,30b)
148         _ASM_EXTABLE(4b,30b)
149         _ASM_EXTABLE(5b,30b)
150         _ASM_EXTABLE(6b,30b)
151         _ASM_EXTABLE(7b,30b)
152         _ASM_EXTABLE(8b,30b)
153         _ASM_EXTABLE(9b,30b)
154         _ASM_EXTABLE(10b,30b)
155         _ASM_EXTABLE(11b,30b)
156         _ASM_EXTABLE(12b,30b)
157         _ASM_EXTABLE(13b,30b)
158         _ASM_EXTABLE(14b,30b)
159         _ASM_EXTABLE(15b,30b)
160         _ASM_EXTABLE(16b,30b)
161         _ASM_EXTABLE(18b,40b)
162         _ASM_EXTABLE(19b,40b)
163         _ASM_EXTABLE(21b,50b)
164         _ASM_EXTABLE(22b,50b)
165         CFI_ENDPROC
166 ENDPROC(copy_user_generic_unrolled)
168 /* Some CPUs run faster using the string copy instructions.
169  * This is also a lot simpler. Use them when possible.
171  * Only 4GB of copy is supported. This shouldn't be a problem
172  * because the kernel normally only writes from/to page sized chunks
173  * even if user space passed a longer buffer.
174  * And more would be dangerous because both Intel and AMD have
175  * errata with rep movsq > 4GB. If someone feels the need to fix
176  * this please consider this.
178  * Input:
179  * rdi destination
180  * rsi source
181  * rdx count
183  * Output:
184  * eax uncopied bytes or 0 if successful.
185  */
186 ENTRY(copy_user_generic_string)
187         CFI_STARTPROC
188         ASM_STAC
189         cmpl $8,%edx
190         jb 2f           /* less than 8 bytes, go to byte copy loop */
191         ALIGN_DESTINATION
192         movl %edx,%ecx
193         shrl $3,%ecx
194         andl $7,%edx
195 1:      rep
196         movsq
197 2:      movl %edx,%ecx
198 3:      rep
199         movsb
200         xorl %eax,%eax
201         ASM_CLAC
202         ret
204         .section .fixup,"ax"
205 11:     leal (%rdx,%rcx,8),%ecx
206 12:     movl %ecx,%edx          /* ecx is zerorest also */
207         jmp copy_user_handle_tail
208         .previous
210         _ASM_EXTABLE(1b,11b)
211         _ASM_EXTABLE(3b,12b)
212         CFI_ENDPROC
213 ENDPROC(copy_user_generic_string)
216  * Some CPUs are adding enhanced REP MOVSB/STOSB instructions.
217  * It's recommended to use enhanced REP MOVSB/STOSB if it's enabled.
219  * Input:
220  * rdi destination
221  * rsi source
222  * rdx count
224  * Output:
225  * eax uncopied bytes or 0 if successful.
226  */
227 ENTRY(copy_user_enhanced_fast_string)
228         CFI_STARTPROC
229         ASM_STAC
230         movl %edx,%ecx
231 1:      rep
232         movsb
233         xorl %eax,%eax
234         ASM_CLAC
235         ret
237         .section .fixup,"ax"
238 12:     movl %ecx,%edx          /* ecx is zerorest also */
239         jmp copy_user_handle_tail
240         .previous
242         _ASM_EXTABLE(1b,12b)
243         CFI_ENDPROC
244 ENDPROC(copy_user_enhanced_fast_string)