Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* Copyright 2002 Andi Kleen, SuSE Labs. |
| 2 | * Subject to the GNU Public License v2. |
| 3 | * |
| 4 | * Functions to copy from and to user space. |
| 5 | */ |
| 6 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7 | #include <asm/current.h> |
Sam Ravnborg | e2d5df9 | 2005-09-09 21:28:48 +0200 | [diff] [blame] | 8 | #include <asm/asm-offsets.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 9 | #include <asm/thread_info.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 10 | |
| 11 | /* Standard copy_to_user with segment limit checking */ |
| 12 | .globl copy_to_user |
| 13 | .p2align 4 |
| 14 | copy_to_user: |
| 15 | GET_THREAD_INFO(%rax) |
| 16 | movq %rdi,%rcx |
| 17 | addq %rdx,%rcx |
| 18 | jc bad_to_user |
| 19 | cmpq threadinfo_addr_limit(%rax),%rcx |
| 20 | jae bad_to_user |
Andi Kleen | 2cbc9ee | 2006-01-11 22:44:45 +0100 | [diff] [blame] | 21 | jmp copy_user_generic |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 22 | |
| 23 | /* Standard copy_from_user with segment limit checking */ |
| 24 | .globl copy_from_user |
| 25 | .p2align 4 |
| 26 | copy_from_user: |
| 27 | GET_THREAD_INFO(%rax) |
| 28 | movq %rsi,%rcx |
| 29 | addq %rdx,%rcx |
| 30 | jc bad_from_user |
| 31 | cmpq threadinfo_addr_limit(%rax),%rcx |
| 32 | jae bad_from_user |
| 33 | /* FALL THROUGH to copy_user_generic */ |
| 34 | |
| 35 | .section .fixup,"ax" |
| 36 | /* must zero dest */ |
| 37 | bad_from_user: |
| 38 | movl %edx,%ecx |
| 39 | xorl %eax,%eax |
| 40 | rep |
| 41 | stosb |
| 42 | bad_to_user: |
| 43 | movl %edx,%eax |
| 44 | ret |
| 45 | .previous |
| 46 | |
| 47 | |
| 48 | /* |
| 49 | * copy_user_generic - memory copy with exception handling. |
| 50 | * |
| 51 | * Input: |
| 52 | * rdi destination |
| 53 | * rsi source |
| 54 | * rdx count |
| 55 | * |
Andi Kleen | 2cbc9ee | 2006-01-11 22:44:45 +0100 | [diff] [blame] | 56 | * Only 4GB of copy is supported. This shouldn't be a problem |
| 57 | * because the kernel normally only writes from/to page sized chunks |
| 58 | * even if user space passed a longer buffer. |
| 59 | * And more would be dangerous because both Intel and AMD have |
| 60 | * errata with rep movsq > 4GB. If someone feels the need to fix |
| 61 | * this please consider this. |
| 62 | * |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 63 | * Output: |
| 64 | * eax uncopied bytes or 0 if successful. |
| 65 | */ |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 66 | |
Andi Kleen | 2cbc9ee | 2006-01-11 22:44:45 +0100 | [diff] [blame] | 67 | .globl copy_user_generic |
| 68 | copy_user_generic: |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 69 | movl %edx,%ecx |
| 70 | shrl $3,%ecx |
| 71 | andl $7,%edx |
Andi Kleen | 2cbc9ee | 2006-01-11 22:44:45 +0100 | [diff] [blame] | 72 | jz 5f |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 73 | 1: rep |
| 74 | movsq |
| 75 | movl %edx,%ecx |
Andi Kleen | 2cbc9ee | 2006-01-11 22:44:45 +0100 | [diff] [blame] | 76 | xor %eax,%eax |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 77 | 2: rep |
| 78 | movsb |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 79 | ret |
Andi Kleen | 2cbc9ee | 2006-01-11 22:44:45 +0100 | [diff] [blame] | 80 | /* align here? */ |
| 81 | 5: xorl %eax,%eax |
| 82 | 6: rep movsq |
| 83 | ret |
| 84 | |
| 85 | .section .fixup,"ax" |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 86 | 3: lea (%rdx,%rcx,8),%rax |
| 87 | ret |
Andi Kleen | 2cbc9ee | 2006-01-11 22:44:45 +0100 | [diff] [blame] | 88 | 4: movl %ecx,%eax |
| 89 | ret |
| 90 | .previous |
| 91 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 92 | .section __ex_table,"a" |
| 93 | .quad 1b,3b |
| 94 | .quad 2b,4b |
Andi Kleen | 2cbc9ee | 2006-01-11 22:44:45 +0100 | [diff] [blame] | 95 | .quad 6b,4b |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 96 | .previous |