x86: streamline copying to/from user memory

Their size parameters being "unsigned", there's neither a point for
them returning "unsigned long", nor for any of their (assembly)
arithmetic to involved 64-bit operations on other than addresses.

Take the opportunity and fold __do_clear_user() into its single user
(using qword stores instead of dword ones), name all asm() operands,
and reduce the amount of (redundant) operands.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
This commit is contained in:
Jan Beulich committed 2016-12-16 14:32:51 +01:00
1 parent f04722f78b
commit 2fdf5b2554
2 files changed
+72 -76

No files matched your search

+67 -71
View File
@@ -10,87 +10,88 @@
#include <xen/sched.h>
#include <asm/uaccess.h>
unsigned long __copy_to_user_ll(void __user *to, const void *from, unsigned n)
unsigned __copy_to_user_ll(void __user *to, const void *from, unsigned n)
{
unsigned long __d0, __d1, __d2, __n = n;
unsigned dummy;
stac();
asm volatile (
" cmp $"STR(2*BYTES_PER_LONG-1)",%0\n"
" cmp $"STR(2*BYTES_PER_LONG-1)", %[cnt]\n"
" jbe 1f\n"
" mov %1,%0\n"
" neg %0\n"
" and $"STR(BYTES_PER_LONG-1)",%0\n"
" sub %0,%3\n"
" mov %k[to], %[cnt]\n"
" neg %[cnt]\n"
" and $"STR(BYTES_PER_LONG-1)", %[cnt]\n"
" sub %[cnt], %[aux]\n"
"4: rep movsb\n" /* make 'to' address aligned */
" mov %3,%0\n"
" shr $"STR(LONG_BYTEORDER)",%0\n"
" and $"STR(BYTES_PER_LONG-1)",%3\n"
" mov %[aux], %[cnt]\n"
" shr $"STR(LONG_BYTEORDER)", %[cnt]\n"
" and $"STR(BYTES_PER_LONG-1)", %[aux]\n"
" .align 2,0x90\n"
"0: rep movs"__OS"\n" /* as many words as possible... */
" mov %3,%0\n"
" mov %[aux],%[cnt]\n"
"1: rep movsb\n" /* ...remainder copied as bytes */
"2:\n"
".section .fixup,\"ax\"\n"
"5: add %3,%0\n"
"5: add %[aux], %[cnt]\n"
" jmp 2b\n"
"3: lea 0(%3,%0,"STR(BYTES_PER_LONG)"),%0\n"
"3: lea (%q[aux], %q[cnt], "STR(BYTES_PER_LONG)"), %[cnt]\n"
" jmp 2b\n"
".previous\n"
_ASM_EXTABLE(4b, 5b)
_ASM_EXTABLE(0b, 3b)
_ASM_EXTABLE(1b, 2b)
: "=&c" (__n), "=&D" (__d0), "=&S" (__d1), "=&r" (__d2)
: "0" (__n), "1" (to), "2" (from), "3" (__n)
: [cnt] "+c" (n), [to] "+D" (to), [from] "+S" (from),
[aux] "=&r" (dummy)
: "[aux]" (n)
: "memory" );
clac();
return __n;
return n;
}
unsigned long
__copy_from_user_ll(void *to, const void __user *from, unsigned n)
unsigned __copy_from_user_ll(void *to, const void __user *from, unsigned n)
{
unsigned long __d0, __d1, __d2, __n = n;
unsigned dummy;
stac();
asm volatile (
" cmp $"STR(2*BYTES_PER_LONG-1)",%0\n"
" cmp $"STR(2*BYTES_PER_LONG-1)", %[cnt]\n"
" jbe 1f\n"
" mov %1,%0\n"
" neg %0\n"
" and $"STR(BYTES_PER_LONG-1)",%0\n"
" sub %0,%3\n"
"4: rep; movsb\n" /* make 'to' address aligned */
" mov %3,%0\n"
" shr $"STR(LONG_BYTEORDER)",%0\n"
" and $"STR(BYTES_PER_LONG-1)",%3\n"
" mov %k[to], %[cnt]\n"
" neg %[cnt]\n"
" and $"STR(BYTES_PER_LONG-1)", %[cnt]\n"
" sub %[cnt], %[aux]\n"
"4: rep movsb\n" /* make 'to' address aligned */
" mov %[aux],%[cnt]\n"
" shr $"STR(LONG_BYTEORDER)", %[cnt]\n"
" and $"STR(BYTES_PER_LONG-1)", %[aux]\n"
" .align 2,0x90\n"
"0: rep; movs"__OS"\n" /* as many words as possible... */
" mov %3,%0\n"
"1: rep; movsb\n" /* ...remainder copied as bytes */
"0: rep movs"__OS"\n" /* as many words as possible... */
" mov %[aux], %[cnt]\n"
"1: rep movsb\n" /* ...remainder copied as bytes */
"2:\n"
".section .fixup,\"ax\"\n"
"5: add %3,%0\n"
"5: add %[aux], %[cnt]\n"
" jmp 6f\n"
"3: lea 0(%3,%0,"STR(BYTES_PER_LONG)"),%0\n"
"6: push %0\n"
" push %%"__OP"ax\n"
" xor %%eax,%%eax\n"
" rep; stosb\n"
" pop %%"__OP"ax\n"
" pop %0\n"
"3: lea (%q[aux], %q[cnt], "STR(BYTES_PER_LONG)"), %[cnt]\n"
"6: mov %[cnt], %k[from]\n"
" xchg %%eax, %[aux]\n"
" xor %%eax, %%eax\n"
" rep stosb\n"
" xchg %[aux], %%eax\n"
" mov %k[from], %[cnt]\n"
" jmp 2b\n"
".previous\n"
_ASM_EXTABLE(4b, 5b)
_ASM_EXTABLE(0b, 3b)
_ASM_EXTABLE(1b, 6b)
: "=&c" (__n), "=&D" (__d0), "=&S" (__d1), "=&r" (__d2)
: "0" (__n), "1" (to), "2" (from), "3" (__n)
: [cnt] "+c" (n), [to] "+D" (to), [from] "+S" (from),
[aux] "=&r" (dummy)
: "[aux]" (n)
: "memory" );
clac();
return __n;
return n;
}
/**
@@ -106,34 +107,13 @@ __copy_from_user_ll(void *to, const void __user *from, unsigned n)
* Returns number of bytes that could not be copied.
* On success, this will be zero.
*/
unsigned long
copy_to_user(void __user *to, const void *from, unsigned n)
unsigned copy_to_user(void __user *to, const void *from, unsigned n)
{
if ( access_ok(to, n) )
n = __copy_to_user(to, from, n);
return n;
}
#define __do_clear_user(addr,size) \
do { \
long __d0; \
stac(); \
__asm__ __volatile__( \
"0: rep; stosl\n" \
" movl %2,%0\n" \
"1: rep; stosb\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"3: lea 0(%2,%0,4),%0\n" \
" jmp 2b\n" \
".previous\n" \
_ASM_EXTABLE(0b,3b) \
_ASM_EXTABLE(1b,2b) \
: "=&c"(size), "=&D" (__d0) \
: "r"(size & 3), "0"(size / 4), "1"((long)addr), "a"(0)); \
clac(); \
} while (0)
/**
* clear_user: - Zero a block of memory in user space.
* @to: Destination address, in user space.
@@ -144,12 +124,29 @@ do { \
* Returns number of bytes that could not be cleared.
* On success, this will be zero.
*/
unsigned long
clear_user(void __user *to, unsigned n)
unsigned clear_user(void __user *to, unsigned n)
{
if ( access_ok(to, n) )
__do_clear_user(to, n);
return n;
if ( access_ok(to, n) )
{
stac();
asm volatile (
"0: rep stos"__OS"\n"
" mov %[bytes], %[cnt]\n"
"1: rep stosb\n"
"2:\n"
".section .fixup,\"ax\"\n"
"3: lea (%q[bytes], %q[longs], "STR(BYTES_PER_LONG)"), %[cnt]\n"
" jmp 2b\n"
".previous\n"
_ASM_EXTABLE(0b,3b)
_ASM_EXTABLE(1b,2b)
: [cnt] "=&c" (n), [to] "+D" (to)
: [bytes] "g" (n & (BYTES_PER_LONG - 1)),
[longs] "0" (n / BYTES_PER_LONG), "a" (0) );
clac();
}
return n;
}
/**
@@ -168,8 +165,7 @@ clear_user(void __user *to, unsigned n)
* If some data could not be copied, this function will pad the copied
* data to the requested size using zero bytes.
*/
unsigned long
copy_from_user(void *to, const void __user *from, unsigned n)
unsigned copy_from_user(void *to, const void __user *from, unsigned n)
{
if ( access_ok(from, n) )
n = __copy_from_user(to, from, n);
+5 -5
View File
@@ -11,12 +11,12 @@
#include <asm/x86_64/uaccess.h>
unsigned long copy_to_user(void *to, const void *from, unsigned len);
unsigned long clear_user(void *to, unsigned len);
unsigned long copy_from_user(void *to, const void *from, unsigned len);
unsigned copy_to_user(void *to, const void *from, unsigned len);
unsigned clear_user(void *to, unsigned len);
unsigned copy_from_user(void *to, const void *from, unsigned len);
/* Handles exceptions in both to and from, but doesn't do access_ok */
unsigned long __copy_to_user_ll(void *to, const void *from, unsigned n);
unsigned long __copy_from_user_ll(void *to, const void *from, unsigned n);
unsigned __copy_to_user_ll(void __user*to, const void *from, unsigned n);
unsigned __copy_from_user_ll(void *to, const void __user *from, unsigned n);
extern long __get_user_bad(void);
extern void __put_user_bad(void);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.