2005-04-17 06:20:36 +08:00
|
|
|
/* Copyright 2002 Andi Kleen, SuSE Labs.
|
|
|
|
* Subject to the GNU Public License v2.
|
|
|
|
*
|
|
|
|
* Functions to copy from and to user space.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <asm/current.h>
|
2005-09-10 03:28:48 +08:00
|
|
|
#include <asm/asm-offsets.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <asm/thread_info.h>
|
|
|
|
|
|
|
|
/* Standard copy_to_user with segment limit checking */
|
|
|
|
.globl copy_to_user
|
|
|
|
.p2align 4
|
|
|
|
copy_to_user:
|
|
|
|
GET_THREAD_INFO(%rax)
|
|
|
|
movq %rdi,%rcx
|
|
|
|
addq %rdx,%rcx
|
|
|
|
jc bad_to_user
|
|
|
|
cmpq threadinfo_addr_limit(%rax),%rcx
|
|
|
|
jae bad_to_user
|
2006-01-12 05:44:45 +08:00
|
|
|
jmp copy_user_generic
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* Standard copy_from_user with segment limit checking */
|
|
|
|
.globl copy_from_user
|
|
|
|
.p2align 4
|
|
|
|
copy_from_user:
|
|
|
|
GET_THREAD_INFO(%rax)
|
|
|
|
movq %rsi,%rcx
|
|
|
|
addq %rdx,%rcx
|
|
|
|
jc bad_from_user
|
|
|
|
cmpq threadinfo_addr_limit(%rax),%rcx
|
|
|
|
jae bad_from_user
|
|
|
|
/* FALL THROUGH to copy_user_generic */
|
|
|
|
|
|
|
|
.section .fixup,"ax"
|
|
|
|
/* must zero dest */
|
|
|
|
bad_from_user:
|
|
|
|
movl %edx,%ecx
|
|
|
|
xorl %eax,%eax
|
|
|
|
rep
|
|
|
|
stosb
|
|
|
|
bad_to_user:
|
|
|
|
movl %edx,%eax
|
|
|
|
ret
|
|
|
|
.previous
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* copy_user_generic - memory copy with exception handling.
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* rdi destination
|
|
|
|
* rsi source
|
|
|
|
* rdx count
|
|
|
|
*
|
2006-01-12 05:44:45 +08:00
|
|
|
* 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.
|
|
|
|
*
|
2005-04-17 06:20:36 +08:00
|
|
|
* Output:
|
|
|
|
* eax uncopied bytes or 0 if successful.
|
|
|
|
*/
|
|
|
|
|
2006-01-12 05:44:45 +08:00
|
|
|
.globl copy_user_generic
|
|
|
|
copy_user_generic:
|
2005-04-17 06:20:36 +08:00
|
|
|
movl %edx,%ecx
|
|
|
|
shrl $3,%ecx
|
|
|
|
andl $7,%edx
|
2006-01-12 05:44:45 +08:00
|
|
|
jz 5f
|
2005-04-17 06:20:36 +08:00
|
|
|
1: rep
|
|
|
|
movsq
|
|
|
|
movl %edx,%ecx
|
2006-01-12 05:44:45 +08:00
|
|
|
xor %eax,%eax
|
2005-04-17 06:20:36 +08:00
|
|
|
2: rep
|
|
|
|
movsb
|
|
|
|
ret
|
2006-01-12 05:44:45 +08:00
|
|
|
/* align here? */
|
|
|
|
5: xorl %eax,%eax
|
|
|
|
6: rep movsq
|
|
|
|
ret
|
|
|
|
|
|
|
|
.section .fixup,"ax"
|
2005-04-17 06:20:36 +08:00
|
|
|
3: lea (%rdx,%rcx,8),%rax
|
|
|
|
ret
|
2006-01-12 05:44:45 +08:00
|
|
|
4: movl %ecx,%eax
|
|
|
|
ret
|
|
|
|
.previous
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
.section __ex_table,"a"
|
|
|
|
.quad 1b,3b
|
|
|
|
.quad 2b,4b
|
2006-01-12 05:44:45 +08:00
|
|
|
.quad 6b,4b
|
2005-04-17 06:20:36 +08:00
|
|
|
.previous
|