First Support on Ginger and OMAP TI
[linux-ginger.git] / arch / x86 / lib / copy_user_64.S
blob6ba0f7bb85eadaeebffde0d428dd8af7f932d2c9
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>
12 #define FIX_ALIGNMENT 1
14 #include <asm/current.h>
15 #include <asm/asm-offsets.h>
16 #include <asm/thread_info.h>
17 #include <asm/cpufeature.h>
19         .macro ALTERNATIVE_JUMP feature,orig,alt
21         .byte 0xe9      /* 32bit jump */
22         .long \orig-1f  /* by default jump to orig */
24         .section .altinstr_replacement,"ax"
25 2:      .byte 0xe9                      /* near jump with 32bit immediate */
26         .long \alt-1b /* offset */   /* or alternatively to alt */
27         .previous
28         .section .altinstructions,"a"
29         .align 8
30         .quad  0b
31         .quad  2b
32         .byte  \feature                 /* when feature is set */
33         .byte  5
34         .byte  5
35         .previous
36         .endm
38         .macro ALIGN_DESTINATION
39 #ifdef FIX_ALIGNMENT
40         /* check for bad alignment of destination */
41         movl %edi,%ecx
42         andl $7,%ecx
43         jz 102f                         /* already aligned */
44         subl $8,%ecx
45         negl %ecx
46         subl %ecx,%edx
47 100:    movb (%rsi),%al
48 101:    movb %al,(%rdi)
49         incq %rsi
50         incq %rdi
51         decl %ecx
52         jnz 100b
53 102:
54         .section .fixup,"ax"
55 103:    addl %ecx,%edx                  /* ecx is zerorest also */
56         jmp copy_user_handle_tail
57         .previous
59         .section __ex_table,"a"
60         .align 8
61         .quad 100b,103b
62         .quad 101b,103b
63         .previous
64 #endif
65         .endm
67 /* Standard copy_to_user with segment limit checking */
68 ENTRY(copy_to_user)
69         CFI_STARTPROC
70         GET_THREAD_INFO(%rax)
71         movq %rdi,%rcx
72         addq %rdx,%rcx
73         jc bad_to_user
74         cmpq TI_addr_limit(%rax),%rcx
75         jae bad_to_user
76         ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
77         CFI_ENDPROC
78 ENDPROC(copy_to_user)
80 /* Standard copy_from_user with segment limit checking */
81 ENTRY(copy_from_user)
82         CFI_STARTPROC
83         GET_THREAD_INFO(%rax)
84         movq %rsi,%rcx
85         addq %rdx,%rcx
86         jc bad_from_user
87         cmpq TI_addr_limit(%rax),%rcx
88         jae bad_from_user
89         ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
90         CFI_ENDPROC
91 ENDPROC(copy_from_user)
93 ENTRY(copy_user_generic)
94         CFI_STARTPROC
95         ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
96         CFI_ENDPROC
97 ENDPROC(copy_user_generic)
99 ENTRY(__copy_from_user_inatomic)
100         CFI_STARTPROC
101         ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
102         CFI_ENDPROC
103 ENDPROC(__copy_from_user_inatomic)
105         .section .fixup,"ax"
106         /* must zero dest */
107 ENTRY(bad_from_user)
108 bad_from_user:
109         CFI_STARTPROC
110         movl %edx,%ecx
111         xorl %eax,%eax
112         rep
113         stosb
114 bad_to_user:
115         movl %edx,%eax
116         ret
117         CFI_ENDPROC
118 ENDPROC(bad_from_user)
119         .previous
122  * copy_user_generic_unrolled - memory copy with exception handling.
123  * This version is for CPUs like P4 that don't have efficient micro
124  * code for rep movsq
126  * Input:
127  * rdi destination
128  * rsi source
129  * rdx count
131  * Output:
132  * eax uncopied bytes or 0 if successfull.
133  */
134 ENTRY(copy_user_generic_unrolled)
135         CFI_STARTPROC
136         cmpl $8,%edx
137         jb 20f          /* less then 8 bytes, go to byte copy loop */
138         ALIGN_DESTINATION
139         movl %edx,%ecx
140         andl $63,%edx
141         shrl $6,%ecx
142         jz 17f
143 1:      movq (%rsi),%r8
144 2:      movq 1*8(%rsi),%r9
145 3:      movq 2*8(%rsi),%r10
146 4:      movq 3*8(%rsi),%r11
147 5:      movq %r8,(%rdi)
148 6:      movq %r9,1*8(%rdi)
149 7:      movq %r10,2*8(%rdi)
150 8:      movq %r11,3*8(%rdi)
151 9:      movq 4*8(%rsi),%r8
152 10:     movq 5*8(%rsi),%r9
153 11:     movq 6*8(%rsi),%r10
154 12:     movq 7*8(%rsi),%r11
155 13:     movq %r8,4*8(%rdi)
156 14:     movq %r9,5*8(%rdi)
157 15:     movq %r10,6*8(%rdi)
158 16:     movq %r11,7*8(%rdi)
159         leaq 64(%rsi),%rsi
160         leaq 64(%rdi),%rdi
161         decl %ecx
162         jnz 1b
163 17:     movl %edx,%ecx
164         andl $7,%edx
165         shrl $3,%ecx
166         jz 20f
167 18:     movq (%rsi),%r8
168 19:     movq %r8,(%rdi)
169         leaq 8(%rsi),%rsi
170         leaq 8(%rdi),%rdi
171         decl %ecx
172         jnz 18b
173 20:     andl %edx,%edx
174         jz 23f
175         movl %edx,%ecx
176 21:     movb (%rsi),%al
177 22:     movb %al,(%rdi)
178         incq %rsi
179         incq %rdi
180         decl %ecx
181         jnz 21b
182 23:     xor %eax,%eax
183         ret
185         .section .fixup,"ax"
186 30:     shll $6,%ecx
187         addl %ecx,%edx
188         jmp 60f
189 40:     lea (%rdx,%rcx,8),%rdx
190         jmp 60f
191 50:     movl %ecx,%edx
192 60:     jmp copy_user_handle_tail /* ecx is zerorest also */
193         .previous
195         .section __ex_table,"a"
196         .align 8
197         .quad 1b,30b
198         .quad 2b,30b
199         .quad 3b,30b
200         .quad 4b,30b
201         .quad 5b,30b
202         .quad 6b,30b
203         .quad 7b,30b
204         .quad 8b,30b
205         .quad 9b,30b
206         .quad 10b,30b
207         .quad 11b,30b
208         .quad 12b,30b
209         .quad 13b,30b
210         .quad 14b,30b
211         .quad 15b,30b
212         .quad 16b,30b
213         .quad 18b,40b
214         .quad 19b,40b
215         .quad 21b,50b
216         .quad 22b,50b
217         .previous
218         CFI_ENDPROC
219 ENDPROC(copy_user_generic_unrolled)
221 /* Some CPUs run faster using the string copy instructions.
222  * This is also a lot simpler. Use them when possible.
224  * Only 4GB of copy is supported. This shouldn't be a problem
225  * because the kernel normally only writes from/to page sized chunks
226  * even if user space passed a longer buffer.
227  * And more would be dangerous because both Intel and AMD have
228  * errata with rep movsq > 4GB. If someone feels the need to fix
229  * this please consider this.
231  * Input:
232  * rdi destination
233  * rsi source
234  * rdx count
236  * Output:
237  * eax uncopied bytes or 0 if successful.
238  */
239 ENTRY(copy_user_generic_string)
240         CFI_STARTPROC
241         andl %edx,%edx
242         jz 4f
243         cmpl $8,%edx
244         jb 2f           /* less than 8 bytes, go to byte copy loop */
245         ALIGN_DESTINATION
246         movl %edx,%ecx
247         shrl $3,%ecx
248         andl $7,%edx
249 1:      rep
250         movsq
251 2:      movl %edx,%ecx
252 3:      rep
253         movsb
254 4:      xorl %eax,%eax
255         ret
257         .section .fixup,"ax"
258 11:     lea (%rdx,%rcx,8),%rcx
259 12:     movl %ecx,%edx          /* ecx is zerorest also */
260         jmp copy_user_handle_tail
261         .previous
263         .section __ex_table,"a"
264         .align 8
265         .quad 1b,11b
266         .quad 3b,12b
267         .previous
268         CFI_ENDPROC
269 ENDPROC(copy_user_generic_string)