| 1 | /* |
|---|
| 2 | * User address space access functions. |
|---|
| 3 | * |
|---|
| 4 | * Copyright 1997 Andi Kleen <ak@muc.de> |
|---|
| 5 | * Copyright 1997 Linus Torvalds |
|---|
| 6 | * Copyright 2002 Andi Kleen <ak@suse.de> |
|---|
| 7 | */ |
|---|
| 8 | |
|---|
| 9 | #include <xen/config.h> |
|---|
| 10 | #include <xen/lib.h> |
|---|
| 11 | #include <asm/uaccess.h> |
|---|
| 12 | |
|---|
| 13 | unsigned long __copy_to_user_ll(void __user *to, const void *from, unsigned n) |
|---|
| 14 | { |
|---|
| 15 | unsigned long __d0, __d1, __d2, __n = n; |
|---|
| 16 | __asm__ __volatile__( |
|---|
| 17 | " cmp $"STR(2*BYTES_PER_LONG-1)",%0\n" |
|---|
| 18 | " jbe 1f\n" |
|---|
| 19 | " mov %1,%0\n" |
|---|
| 20 | " neg %0\n" |
|---|
| 21 | " and $"STR(BYTES_PER_LONG-1)",%0\n" |
|---|
| 22 | " sub %0,%3\n" |
|---|
| 23 | "4: rep; movsb\n" /* make 'to' address aligned */ |
|---|
| 24 | " mov %3,%0\n" |
|---|
| 25 | " shr $"STR(LONG_BYTEORDER)",%0\n" |
|---|
| 26 | " and $"STR(BYTES_PER_LONG-1)",%3\n" |
|---|
| 27 | " .align 2,0x90\n" |
|---|
| 28 | "0: rep; movs"__OS"\n" /* as many words as possible... */ |
|---|
| 29 | " mov %3,%0\n" |
|---|
| 30 | "1: rep; movsb\n" /* ...remainder copied as bytes */ |
|---|
| 31 | "2:\n" |
|---|
| 32 | ".section .fixup,\"ax\"\n" |
|---|
| 33 | "5: add %3,%0\n" |
|---|
| 34 | " jmp 2b\n" |
|---|
| 35 | "3: lea 0(%3,%0,"STR(BYTES_PER_LONG)"),%0\n" |
|---|
| 36 | " jmp 2b\n" |
|---|
| 37 | ".previous\n" |
|---|
| 38 | ".section __ex_table,\"a\"\n" |
|---|
| 39 | " "__FIXUP_ALIGN"\n" |
|---|
| 40 | " "__FIXUP_WORD" 4b,5b\n" |
|---|
| 41 | " "__FIXUP_WORD" 0b,3b\n" |
|---|
| 42 | " "__FIXUP_WORD" 1b,2b\n" |
|---|
| 43 | ".previous" |
|---|
| 44 | : "=&c"(__n), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) |
|---|
| 45 | : "3"(__n), "0"(__n), "1"(to), "2"(from) |
|---|
| 46 | : "memory"); |
|---|
| 47 | return (unsigned)__n; |
|---|
| 48 | } |
|---|
| 49 | |
|---|
| 50 | unsigned long |
|---|
| 51 | __copy_from_user_ll(void *to, const void __user *from, unsigned n) |
|---|
| 52 | { |
|---|
| 53 | unsigned long __d0, __d1, __d2, __n = n; |
|---|
| 54 | __asm__ __volatile__( |
|---|
| 55 | " cmp $"STR(2*BYTES_PER_LONG-1)",%0\n" |
|---|
| 56 | " jbe 1f\n" |
|---|
| 57 | " mov %1,%0\n" |
|---|
| 58 | " neg %0\n" |
|---|
| 59 | " and $"STR(BYTES_PER_LONG-1)",%0\n" |
|---|
| 60 | " sub %0,%3\n" |
|---|
| 61 | "4: rep; movsb\n" /* make 'to' address aligned */ |
|---|
| 62 | " mov %3,%0\n" |
|---|
| 63 | " shr $"STR(LONG_BYTEORDER)",%0\n" |
|---|
| 64 | " and $"STR(BYTES_PER_LONG-1)",%3\n" |
|---|
| 65 | " .align 2,0x90\n" |
|---|
| 66 | "0: rep; movs"__OS"\n" /* as many words as possible... */ |
|---|
| 67 | " mov %3,%0\n" |
|---|
| 68 | "1: rep; movsb\n" /* ...remainder copied as bytes */ |
|---|
| 69 | "2:\n" |
|---|
| 70 | ".section .fixup,\"ax\"\n" |
|---|
| 71 | "5: add %3,%0\n" |
|---|
| 72 | " jmp 6f\n" |
|---|
| 73 | "3: lea 0(%3,%0,"STR(BYTES_PER_LONG)"),%0\n" |
|---|
| 74 | "6: push %0\n" |
|---|
| 75 | " push %%"__OP"ax\n" |
|---|
| 76 | " xor %%eax,%%eax\n" |
|---|
| 77 | " rep; stosb\n" |
|---|
| 78 | " pop %%"__OP"ax\n" |
|---|
| 79 | " pop %0\n" |
|---|
| 80 | " jmp 2b\n" |
|---|
| 81 | ".previous\n" |
|---|
| 82 | ".section __ex_table,\"a\"\n" |
|---|
| 83 | " "__FIXUP_ALIGN"\n" |
|---|
| 84 | " "__FIXUP_WORD" 4b,5b\n" |
|---|
| 85 | " "__FIXUP_WORD" 0b,3b\n" |
|---|
| 86 | " "__FIXUP_WORD" 1b,6b\n" |
|---|
| 87 | ".previous" |
|---|
| 88 | : "=&c"(__n), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) |
|---|
| 89 | : "3"(__n), "0"(__n), "1"(to), "2"(from) |
|---|
| 90 | : "memory"); |
|---|
| 91 | return (unsigned)__n; |
|---|
| 92 | } |
|---|
| 93 | |
|---|
| 94 | /** |
|---|
| 95 | * copy_to_user: - Copy a block of data into user space. |
|---|
| 96 | * @to: Destination address, in user space. |
|---|
| 97 | * @from: Source address, in kernel space. |
|---|
| 98 | * @n: Number of bytes to copy. |
|---|
| 99 | * |
|---|
| 100 | * Context: User context only. This function may sleep. |
|---|
| 101 | * |
|---|
| 102 | * Copy data from kernel space to user space. |
|---|
| 103 | * |
|---|
| 104 | * Returns number of bytes that could not be copied. |
|---|
| 105 | * On success, this will be zero. |
|---|
| 106 | */ |
|---|
| 107 | unsigned long |
|---|
| 108 | copy_to_user(void __user *to, const void *from, unsigned n) |
|---|
| 109 | { |
|---|
| 110 | if (access_ok(to, n)) |
|---|
| 111 | n = __copy_to_user(to, from, n); |
|---|
| 112 | return n; |
|---|
| 113 | } |
|---|
| 114 | |
|---|
| 115 | /** |
|---|
| 116 | * copy_from_user: - Copy a block of data from user space. |
|---|
| 117 | * @to: Destination address, in kernel space. |
|---|
| 118 | * @from: Source address, in user space. |
|---|
| 119 | * @n: Number of bytes to copy. |
|---|
| 120 | * |
|---|
| 121 | * Context: User context only. This function may sleep. |
|---|
| 122 | * |
|---|
| 123 | * Copy data from user space to kernel space. |
|---|
| 124 | * |
|---|
| 125 | * Returns number of bytes that could not be copied. |
|---|
| 126 | * On success, this will be zero. |
|---|
| 127 | * |
|---|
| 128 | * If some data could not be copied, this function will pad the copied |
|---|
| 129 | * data to the requested size using zero bytes. |
|---|
| 130 | */ |
|---|
| 131 | unsigned long |
|---|
| 132 | copy_from_user(void *to, const void __user *from, unsigned n) |
|---|
| 133 | { |
|---|
| 134 | if (access_ok(from, n)) |
|---|
| 135 | n = __copy_from_user(to, from, n); |
|---|
| 136 | else |
|---|
| 137 | memset(to, 0, n); |
|---|
| 138 | return n; |
|---|
| 139 | } |
|---|