x86/uaccess/64: Make the __copy_user_nocache() assembly code more readable
[pandora-kernel.git] / arch / x86 / lib / copy_user_nocache_64.S
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  */
8
9 #include <linux/linkage.h>
10 #include <asm/dwarf2.h>
11
12 #define FIX_ALIGNMENT 1
13
14 #include <asm/current.h>
15 #include <asm/asm-offsets.h>
16 #include <asm/thread_info.h>
17 #include <asm/asm.h>
18
19         .macro ALIGN_DESTINATION
20 #ifdef FIX_ALIGNMENT
21         /* check for bad alignment of destination */
22         movl %edi,%ecx
23         andl $7,%ecx
24         jz 102f                         /* already aligned */
25         subl $8,%ecx
26         negl %ecx
27         subl %ecx,%edx
28 100:    movb (%rsi),%al
29 101:    movb %al,(%rdi)
30         incq %rsi
31         incq %rdi
32         decl %ecx
33         jnz 100b
34 102:
35         .section .fixup,"ax"
36 103:    addl %ecx,%edx                  /* ecx is zerorest also */
37         jmp copy_user_handle_tail
38         .previous
39
40         _ASM_EXTABLE(100b,103b)
41         _ASM_EXTABLE(101b,103b)
42 #endif
43         .endm
44
45 /*
46  * copy_user_nocache - Uncached memory copy with exception handling
47  * This will force destination out of cache for more performance.
48  *
49  * Note: Cached memory copy is used when destination or size is not
50  * naturally aligned. That is:
51  *  - Require 8-byte alignment when size is 8 bytes or larger.
52  */
53 ENTRY(__copy_user_nocache)
54         CFI_STARTPROC
55
56         /* If size is less than 8 bytes, go to byte copy */
57         cmpl $8,%edx
58         jb .L_1b_cache_copy_entry
59
60         /* If destination is not 8-byte aligned, "cache" copy to align it */
61         ALIGN_DESTINATION
62
63         /* Set 4x8-byte copy count and remainder */
64         movl %edx,%ecx
65         andl $63,%edx
66         shrl $6,%ecx
67         jz .L_8b_nocache_copy_entry     /* jump if count is 0 */
68
69         /* Perform 4x8-byte nocache loop-copy */
70 .L_4x8b_nocache_copy_loop:
71 1:      movq (%rsi),%r8
72 2:      movq 1*8(%rsi),%r9
73 3:      movq 2*8(%rsi),%r10
74 4:      movq 3*8(%rsi),%r11
75 5:      movnti %r8,(%rdi)
76 6:      movnti %r9,1*8(%rdi)
77 7:      movnti %r10,2*8(%rdi)
78 8:      movnti %r11,3*8(%rdi)
79 9:      movq 4*8(%rsi),%r8
80 10:     movq 5*8(%rsi),%r9
81 11:     movq 6*8(%rsi),%r10
82 12:     movq 7*8(%rsi),%r11
83 13:     movnti %r8,4*8(%rdi)
84 14:     movnti %r9,5*8(%rdi)
85 15:     movnti %r10,6*8(%rdi)
86 16:     movnti %r11,7*8(%rdi)
87         leaq 64(%rsi),%rsi
88         leaq 64(%rdi),%rdi
89         decl %ecx
90         jnz .L_4x8b_nocache_copy_loop
91
92         /* Set 8-byte copy count and remainder */
93 .L_8b_nocache_copy_entry:
94         movl %edx,%ecx
95         andl $7,%edx
96         shrl $3,%ecx
97         jz .L_1b_cache_copy_entry       /* jump if count is 0 */
98
99         /* Perform 8-byte nocache loop-copy */
100 .L_8b_nocache_copy_loop:
101 20:     movq (%rsi),%r8
102 21:     movnti %r8,(%rdi)
103         leaq 8(%rsi),%rsi
104         leaq 8(%rdi),%rdi
105         decl %ecx
106         jnz .L_8b_nocache_copy_loop
107
108         /* If no byte left, we're done */
109 .L_1b_cache_copy_entry:
110         andl %edx,%edx
111         jz .L_finish_copy
112
113         /* Perform byte "cache" loop-copy for the remainder */
114         movl %edx,%ecx
115 .L_1b_cache_copy_loop:
116 40:     movb (%rsi),%al
117 41:     movb %al,(%rdi)
118         incq %rsi
119         incq %rdi
120         decl %ecx
121         jnz .L_1b_cache_copy_loop
122
123         /* Finished copying; fence the prior stores */
124 .L_finish_copy:
125         xorl %eax,%eax
126         sfence
127         ret
128
129         .section .fixup,"ax"
130 .L_fixup_4x8b_copy:
131         shll $6,%ecx
132         addl %ecx,%edx
133         jmp .L_fixup_handle_tail
134 .L_fixup_8b_copy:
135         lea (%rdx,%rcx,8),%rdx
136         jmp .L_fixup_handle_tail
137 .L_fixup_1b_copy:
138         movl %ecx,%edx
139 .L_fixup_handle_tail:
140         sfence
141         jmp copy_user_handle_tail
142         .previous
143
144         _ASM_EXTABLE(1b,.L_fixup_4x8b_copy)
145         _ASM_EXTABLE(2b,.L_fixup_4x8b_copy)
146         _ASM_EXTABLE(3b,.L_fixup_4x8b_copy)
147         _ASM_EXTABLE(4b,.L_fixup_4x8b_copy)
148         _ASM_EXTABLE(5b,.L_fixup_4x8b_copy)
149         _ASM_EXTABLE(6b,.L_fixup_4x8b_copy)
150         _ASM_EXTABLE(7b,.L_fixup_4x8b_copy)
151         _ASM_EXTABLE(8b,.L_fixup_4x8b_copy)
152         _ASM_EXTABLE(9b,.L_fixup_4x8b_copy)
153         _ASM_EXTABLE(10b,.L_fixup_4x8b_copy)
154         _ASM_EXTABLE(11b,.L_fixup_4x8b_copy)
155         _ASM_EXTABLE(12b,.L_fixup_4x8b_copy)
156         _ASM_EXTABLE(13b,.L_fixup_4x8b_copy)
157         _ASM_EXTABLE(14b,.L_fixup_4x8b_copy)
158         _ASM_EXTABLE(15b,.L_fixup_4x8b_copy)
159         _ASM_EXTABLE(16b,.L_fixup_4x8b_copy)
160         _ASM_EXTABLE(20b,.L_fixup_8b_copy)
161         _ASM_EXTABLE(21b,.L_fixup_8b_copy)
162         _ASM_EXTABLE(40b,.L_fixup_1b_copy)
163         _ASM_EXTABLE(41b,.L_fixup_1b_copy)
164         CFI_ENDPROC
165 ENDPROC(__copy_user_nocache)