copy_user_64.S 6.0 KB
Newer Older
V
Vitaly Mayatskikh 已提交
1 2 3
/*
 * Copyright 2008 Vitaly Mayatskikh <vmayatsk@redhat.com>
 * Copyright 2002 Andi Kleen, SuSE Labs.
L
Linus Torvalds 已提交
4
 * Subject to the GNU Public License v2.
V
Vitaly Mayatskikh 已提交
5 6 7
 *
 * Functions to copy from and to user space.
 */
L
Linus Torvalds 已提交
8

9 10 11
#include <linux/linkage.h>
#include <asm/dwarf2.h>

12 13
#define FIX_ALIGNMENT 1

14 15 16 17
#include <asm/current.h>
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
#include <asm/cpufeature.h>
18
#include <asm/alternative-asm.h>
19

20 21 22 23 24 25 26 27
/*
 * By placing feature2 after feature1 in altinstructions section, we logically
 * implement:
 * If CPU has feature2, jmp to alt2 is used
 * else if CPU has feature1, jmp to alt1 is used
 * else jmp to orig is used.
 */
	.macro ALTERNATIVE_JUMP feature1,feature2,orig,alt1,alt2
28 29 30 31 32
0:
	.byte 0xe9	/* 32bit jump */
	.long \orig-1f	/* by default jump to orig */
1:
	.section .altinstr_replacement,"ax"
V
Vitaly Mayatskikh 已提交
33
2:	.byte 0xe9			/* near jump with 32bit immediate */
34 35 36
	.long \alt1-1b /* offset */   /* or alternatively to alt1 */
3:	.byte 0xe9			/* near jump with 32bit immediate */
	.long \alt2-1b /* offset */   /* or alternatively to alt2 */
37
	.previous
38

39
	.section .altinstructions,"a"
40 41
	altinstruction_entry 0b,2b,\feature1,5,5
	altinstruction_entry 0b,3b,\feature2,5,5
42 43
	.previous
	.endm
L
Linus Torvalds 已提交
44

V
Vitaly Mayatskikh 已提交
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
	.macro ALIGN_DESTINATION
#ifdef FIX_ALIGNMENT
	/* check for bad alignment of destination */
	movl %edi,%ecx
	andl $7,%ecx
	jz 102f				/* already aligned */
	subl $8,%ecx
	negl %ecx
	subl %ecx,%edx
100:	movb (%rsi),%al
101:	movb %al,(%rdi)
	incq %rsi
	incq %rdi
	decl %ecx
	jnz 100b
102:
	.section .fixup,"ax"
62
103:	addl %ecx,%edx			/* ecx is zerorest also */
V
Vitaly Mayatskikh 已提交
63 64 65 66 67 68 69 70 71 72 73 74
	jmp copy_user_handle_tail
	.previous

	.section __ex_table,"a"
	.align 8
	.quad 100b,103b
	.quad 101b,103b
	.previous
#endif
	.endm

/* Standard copy_to_user with segment limit checking */
75
ENTRY(_copy_to_user)
76
	CFI_STARTPROC
L
Linus Torvalds 已提交
77 78 79
	GET_THREAD_INFO(%rax)
	movq %rdi,%rcx
	addq %rdx,%rcx
V
Vitaly Mayatskikh 已提交
80
	jc bad_to_user
G
Glauber Costa 已提交
81
	cmpq TI_addr_limit(%rax),%rcx
82
	ja bad_to_user
83 84 85
	ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,X86_FEATURE_ERMS,	\
		copy_user_generic_unrolled,copy_user_generic_string,	\
		copy_user_enhanced_fast_string
86
	CFI_ENDPROC
87
ENDPROC(_copy_to_user)
88

V
Vitaly Mayatskikh 已提交
89
/* Standard copy_from_user with segment limit checking */
90
ENTRY(_copy_from_user)
91
	CFI_STARTPROC
V
Vitaly Mayatskikh 已提交
92 93 94 95 96
	GET_THREAD_INFO(%rax)
	movq %rsi,%rcx
	addq %rdx,%rcx
	jc bad_from_user
	cmpq TI_addr_limit(%rax),%rcx
97
	ja bad_from_user
98 99 100
	ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,X86_FEATURE_ERMS,	\
		copy_user_generic_unrolled,copy_user_generic_string,	\
		copy_user_enhanced_fast_string
101
	CFI_ENDPROC
102
ENDPROC(_copy_from_user)
103

L
Linus Torvalds 已提交
104 105
	.section .fixup,"ax"
	/* must zero dest */
V
Vitaly Mayatskikh 已提交
106
ENTRY(bad_from_user)
L
Linus Torvalds 已提交
107
bad_from_user:
108
	CFI_STARTPROC
L
Linus Torvalds 已提交
109 110 111 112 113
	movl %edx,%ecx
	xorl %eax,%eax
	rep
	stosb
bad_to_user:
V
Vitaly Mayatskikh 已提交
114
	movl %edx,%eax
L
Linus Torvalds 已提交
115
	ret
116
	CFI_ENDPROC
V
Vitaly Mayatskikh 已提交
117
ENDPROC(bad_from_user)
L
Linus Torvalds 已提交
118
	.previous
V
Vitaly Mayatskikh 已提交
119

L
Linus Torvalds 已提交
120
/*
121
 * copy_user_generic_unrolled - memory copy with exception handling.
V
Vitaly Mayatskikh 已提交
122 123 124 125
 * This version is for CPUs like P4 that don't have efficient micro
 * code for rep movsq
 *
 * Input:
L
Linus Torvalds 已提交
126 127 128 129
 * rdi destination
 * rsi source
 * rdx count
 *
V
Vitaly Mayatskikh 已提交
130
 * Output:
L
Lucas De Marchi 已提交
131
 * eax uncopied bytes or 0 if successful.
L
Linus Torvalds 已提交
132
 */
133
ENTRY(copy_user_generic_unrolled)
134
	CFI_STARTPROC
V
Vitaly Mayatskikh 已提交
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
	cmpl $8,%edx
	jb 20f		/* less then 8 bytes, go to byte copy loop */
	ALIGN_DESTINATION
	movl %edx,%ecx
	andl $63,%edx
	shrl $6,%ecx
	jz 17f
1:	movq (%rsi),%r8
2:	movq 1*8(%rsi),%r9
3:	movq 2*8(%rsi),%r10
4:	movq 3*8(%rsi),%r11
5:	movq %r8,(%rdi)
6:	movq %r9,1*8(%rdi)
7:	movq %r10,2*8(%rdi)
8:	movq %r11,3*8(%rdi)
9:	movq 4*8(%rsi),%r8
10:	movq 5*8(%rsi),%r9
11:	movq 6*8(%rsi),%r10
12:	movq 7*8(%rsi),%r11
13:	movq %r8,4*8(%rdi)
14:	movq %r9,5*8(%rdi)
15:	movq %r10,6*8(%rdi)
16:	movq %r11,7*8(%rdi)
158 159 160
	leaq 64(%rsi),%rsi
	leaq 64(%rdi),%rdi
	decl %ecx
V
Vitaly Mayatskikh 已提交
161 162 163 164 165 166 167
	jnz 1b
17:	movl %edx,%ecx
	andl $7,%edx
	shrl $3,%ecx
	jz 20f
18:	movq (%rsi),%r8
19:	movq %r8,(%rdi)
168
	leaq 8(%rsi),%rsi
V
Vitaly Mayatskikh 已提交
169 170 171 172 173
	leaq 8(%rdi),%rdi
	decl %ecx
	jnz 18b
20:	andl %edx,%edx
	jz 23f
174
	movl %edx,%ecx
V
Vitaly Mayatskikh 已提交
175 176
21:	movb (%rsi),%al
22:	movb %al,(%rdi)
177
	incq %rsi
V
Vitaly Mayatskikh 已提交
178
	incq %rdi
179
	decl %ecx
V
Vitaly Mayatskikh 已提交
180 181
	jnz 21b
23:	xor %eax,%eax
182 183
	ret

V
Vitaly Mayatskikh 已提交
184 185 186 187
	.section .fixup,"ax"
30:	shll $6,%ecx
	addl %ecx,%edx
	jmp 60f
188
40:	lea (%rdx,%rcx,8),%rdx
V
Vitaly Mayatskikh 已提交
189 190 191 192
	jmp 60f
50:	movl %ecx,%edx
60:	jmp copy_user_handle_tail /* ecx is zerorest also */
	.previous
193 194 195

	.section __ex_table,"a"
	.align 8
V
Vitaly Mayatskikh 已提交
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
	.quad 1b,30b
	.quad 2b,30b
	.quad 3b,30b
	.quad 4b,30b
	.quad 5b,30b
	.quad 6b,30b
	.quad 7b,30b
	.quad 8b,30b
	.quad 9b,30b
	.quad 10b,30b
	.quad 11b,30b
	.quad 12b,30b
	.quad 13b,30b
	.quad 14b,30b
	.quad 15b,30b
	.quad 16b,30b
	.quad 18b,40b
	.quad 19b,40b
	.quad 21b,50b
	.quad 22b,50b
216
	.previous
217
	CFI_ENDPROC
V
Vitaly Mayatskikh 已提交
218
ENDPROC(copy_user_generic_unrolled)
219

V
Vitaly Mayatskikh 已提交
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
/* Some CPUs run faster using the string copy instructions.
 * This is also a lot simpler. Use them when possible.
 *
 * Only 4GB of copy is supported. This shouldn't be a problem
 * because the kernel normally only writes from/to page sized chunks
 * even if user space passed a longer buffer.
 * And more would be dangerous because both Intel and AMD have
 * errata with rep movsq > 4GB. If someone feels the need to fix
 * this please consider this.
 *
 * Input:
 * rdi destination
 * rsi source
 * rdx count
 *
 * Output:
 * eax uncopied bytes or 0 if successful.
 */
238
ENTRY(copy_user_generic_string)
239
	CFI_STARTPROC
V
Vitaly Mayatskikh 已提交
240 241 242 243 244
	andl %edx,%edx
	jz 4f
	cmpl $8,%edx
	jb 2f		/* less than 8 bytes, go to byte copy loop */
	ALIGN_DESTINATION
L
Linus Torvalds 已提交
245 246
	movl %edx,%ecx
	shrl $3,%ecx
V
Vitaly Mayatskikh 已提交
247 248
	andl $7,%edx
1:	rep
249
	movsq
V
Vitaly Mayatskikh 已提交
250 251 252 253
2:	movl %edx,%ecx
3:	rep
	movsb
4:	xorl %eax,%eax
L
Linus Torvalds 已提交
254
	ret
255

V
Vitaly Mayatskikh 已提交
256
	.section .fixup,"ax"
257
11:	lea (%rdx,%rcx,8),%rcx
V
Vitaly Mayatskikh 已提交
258 259 260
12:	movl %ecx,%edx		/* ecx is zerorest also */
	jmp copy_user_handle_tail
	.previous
261

L
Linus Torvalds 已提交
262
	.section __ex_table,"a"
V
Vitaly Mayatskikh 已提交
263 264 265
	.align 8
	.quad 1b,11b
	.quad 3b,12b
L
Linus Torvalds 已提交
266
	.previous
V
Vitaly Mayatskikh 已提交
267 268
	CFI_ENDPROC
ENDPROC(copy_user_generic_string)
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302

/*
 * Some CPUs are adding enhanced REP MOVSB/STOSB instructions.
 * It's recommended to use enhanced REP MOVSB/STOSB if it's enabled.
 *
 * Input:
 * rdi destination
 * rsi source
 * rdx count
 *
 * Output:
 * eax uncopied bytes or 0 if successful.
 */
ENTRY(copy_user_enhanced_fast_string)
	CFI_STARTPROC
	andl %edx,%edx
	jz 2f
	movl %edx,%ecx
1:	rep
	movsb
2:	xorl %eax,%eax
	ret

	.section .fixup,"ax"
12:	movl %ecx,%edx		/* ecx is zerorest also */
	jmp copy_user_handle_tail
	.previous

	.section __ex_table,"a"
	.align 8
	.quad 1b,12b
	.previous
	CFI_ENDPROC
ENDPROC(copy_user_enhanced_fast_string)