From f8dd0d3c62164160c59034a96eb17d69ac8a0328 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 9 Jul 2008 09:12:55 +0200 Subject: x86: delay lib unification build fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix: arch/x86/lib/delay.c:93:24: error: macro "use_tsc_delay" passed 1 arguments, but takes just 0 arch/x86/lib/delay.c:94: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘{’ token Signed-off-by: Ingo Molnar --- include/asm-x86/delay.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'include') diff --git a/include/asm-x86/delay.h b/include/asm-x86/delay.h index bb80880c834b..409a649204aa 100644 --- a/include/asm-x86/delay.h +++ b/include/asm-x86/delay.h @@ -26,10 +26,6 @@ extern void __delay(unsigned long loops); ((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \ __ndelay(n)) -#ifdef CONFIG_X86_32 void use_tsc_delay(void); -#else -#define use_tsc_delay() {} -#endif #endif /* _ASM_X86_DELAY_H */ -- cgit v1.2.2 From edf10162b2c5ad78ada8e63e960f9d0949c6c219 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Fri, 13 Jun 2008 16:35:52 -0300 Subject: x86: don't clobber r8 nor use rcx. There's really no reason to clobber r8 or pass the address in rcx. We can safely use only two registers (which we already have to touch anyway) to do the job. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess_64.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'include') diff --git a/include/asm-x86/uaccess_64.h b/include/asm-x86/uaccess_64.h index b8a2f4339903..a2d49078e19c 100644 --- a/include/asm-x86/uaccess_64.h +++ b/include/asm-x86/uaccess_64.h @@ -90,8 +90,7 @@ extern int fixup_exception(struct pt_regs *regs); #define __get_user_x(size, ret, x, ptr) \ asm volatile("call __get_user_" #size \ : "=a" (ret),"=d" (x) \ - : "c" (ptr) \ - : "r8") + : "0" (ptr)) \ /* Careful: we have to cast the result to the type of the pointer * for sign reasons */ -- cgit v1.2.2 From 40faf463e62de0b29722910eded7dd26cd8b684b Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Tue, 24 Jun 2008 11:37:57 -0300 Subject: x86: introduce __ASM_REG macro. There are situations in which the architecture wants to use the register that represents its word-size, whatever it is. For those, introduce __ASM_REG in asm.h, along with the first users _ASM_AX and _ASM_DX. They have users waiting for it, namely the getuser functions. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/asm.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/asm-x86/asm.h b/include/asm-x86/asm.h index 70939820c55f..435402e623e1 100644 --- a/include/asm-x86/asm.h +++ b/include/asm-x86/asm.h @@ -14,6 +14,7 @@ #endif #define __ASM_SIZE(inst) __ASM_SEL(inst##l, inst##q) +#define __ASM_REG(reg) __ASM_SEL(e##reg, r##reg) #define _ASM_PTR __ASM_SEL(.long, .quad) #define _ASM_ALIGN __ASM_SEL(.balign 4, .balign 8) @@ -24,6 +25,8 @@ #define _ASM_ADD __ASM_SIZE(add) #define _ASM_SUB __ASM_SIZE(sub) #define _ASM_XADD __ASM_SIZE(xadd) +#define _ASM_AX __ASM_REG(ax) +#define _ASM_DX __ASM_REG(dx) /* Exception table entry */ # define _ASM_EXTABLE(from,to) \ -- cgit v1.2.2 From 6c2d458680d49d939ffd4b4cdc84d9e004d65910 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Tue, 24 Jun 2008 12:05:11 -0300 Subject: x86: merge getuser asm functions. getuser_32.S and getuser_64.S are merged into getuser.S. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/asm.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-x86/asm.h b/include/asm-x86/asm.h index 435402e623e1..57750a95685d 100644 --- a/include/asm-x86/asm.h +++ b/include/asm-x86/asm.h @@ -3,8 +3,10 @@ #ifdef __ASSEMBLY__ # define __ASM_FORM(x) x +# define __ASM_EX_SEC .section __ex_table #else # define __ASM_FORM(x) " " #x " " +# define __ASM_EX_SEC " .section __ex_table,\"a\"\n" #endif #ifdef CONFIG_X86_32 @@ -30,7 +32,7 @@ /* Exception table entry */ # define _ASM_EXTABLE(from,to) \ - " .section __ex_table,\"a\"\n" \ + __ASM_EX_SEC \ _ASM_ALIGN "\n" \ _ASM_PTR #from "," #to "\n" \ " .previous\n" -- cgit v1.2.2 From 268cf048c890d10bd3a86bd87922ed8a722d502f Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Tue, 24 Jun 2008 12:40:55 -0300 Subject: x86: don't save ebx in putuser_32.S. Clobber it in the inline asm macros, and let the compiler do this for us. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess_32.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/asm-x86/uaccess_32.h b/include/asm-x86/uaccess_32.h index 8e7595c1f34e..0ecfe47ad60d 100644 --- a/include/asm-x86/uaccess_32.h +++ b/include/asm-x86/uaccess_32.h @@ -188,23 +188,23 @@ extern void __put_user_8(void); #define __put_user_1(x, ptr) \ asm volatile("call __put_user_1" : "=a" (__ret_pu) \ - : "0" ((typeof(*(ptr)))(x)), "c" (ptr)) + : "0" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx") #define __put_user_2(x, ptr) \ asm volatile("call __put_user_2" : "=a" (__ret_pu) \ - : "0" ((typeof(*(ptr)))(x)), "c" (ptr)) + : "0" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx") #define __put_user_4(x, ptr) \ asm volatile("call __put_user_4" : "=a" (__ret_pu) \ - : "0" ((typeof(*(ptr)))(x)), "c" (ptr)) + : "0" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx") #define __put_user_8(x, ptr) \ asm volatile("call __put_user_8" : "=a" (__ret_pu) \ - : "A" ((typeof(*(ptr)))(x)), "c" (ptr)) + : "A" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx") #define __put_user_X(x, ptr) \ asm volatile("call __put_user_X" : "=a" (__ret_pu) \ - : "c" (ptr)) + : "c" (ptr): "ebx") /** * put_user: - Write a simple value into user space. -- cgit v1.2.2 From 70706e432ee5618abf59381101d8dea7b8d97a7d Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Tue, 24 Jun 2008 15:02:31 -0300 Subject: x86: user put_user_x instead of all variants. Follow the pattern, and define a single put_user_x, instead of defining macros for all available sizes. Exception is put_user_8, since the "A" constraint does not give us enough power to specify which register (a or d) to use in the 32-bit common case. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess_32.h | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/include/asm-x86/uaccess_32.h b/include/asm-x86/uaccess_32.h index 0ecfe47ad60d..f8abc12a77c2 100644 --- a/include/asm-x86/uaccess_32.h +++ b/include/asm-x86/uaccess_32.h @@ -186,25 +186,14 @@ extern void __put_user_2(void); extern void __put_user_4(void); extern void __put_user_8(void); -#define __put_user_1(x, ptr) \ - asm volatile("call __put_user_1" : "=a" (__ret_pu) \ - : "0" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx") - -#define __put_user_2(x, ptr) \ - asm volatile("call __put_user_2" : "=a" (__ret_pu) \ - : "0" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx") - -#define __put_user_4(x, ptr) \ - asm volatile("call __put_user_4" : "=a" (__ret_pu) \ - : "0" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx") +#define __put_user_x(size, x, ptr) \ + asm volatile("call __put_user_" #size : "=a" (__ret_pu) \ + :"0" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx") #define __put_user_8(x, ptr) \ asm volatile("call __put_user_8" : "=a" (__ret_pu) \ : "A" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx") -#define __put_user_X(x, ptr) \ - asm volatile("call __put_user_X" : "=a" (__ret_pu) \ - : "c" (ptr): "ebx") /** * put_user: - Write a simple value into user space. @@ -232,19 +221,19 @@ extern void __put_user_8(void); __pu_val = x; \ switch (sizeof(*(ptr))) { \ case 1: \ - __put_user_1(__pu_val, ptr); \ + __put_user_x(1, __pu_val, ptr); \ break; \ case 2: \ - __put_user_2(__pu_val, ptr); \ + __put_user_x(2, __pu_val, ptr); \ break; \ case 4: \ - __put_user_4(__pu_val, ptr); \ + __put_user_x(4, __pu_val, ptr); \ break; \ case 8: \ __put_user_8(__pu_val, ptr); \ break; \ default: \ - __put_user_X(__pu_val, ptr); \ + __put_user_x(X, __pu_val, ptr); \ break; \ } \ __ret_pu; \ -- cgit v1.2.2 From 770546b99fb99e71a3aa4181980d42664f9c18bd Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Tue, 24 Jun 2008 15:03:40 -0300 Subject: x86: clobber rbx in putuser_64.S. Instead of clobbering r8, clobber rbx, which is the i386 way. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess_64.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-x86/uaccess_64.h b/include/asm-x86/uaccess_64.h index a2d49078e19c..21fda9ebee13 100644 --- a/include/asm-x86/uaccess_64.h +++ b/include/asm-x86/uaccess_64.h @@ -131,7 +131,7 @@ extern void __put_user_bad(void); asm volatile("call __put_user_" #size \ :"=a" (ret) \ :"c" (ptr),"d" (x) \ - :"r8") + :"ebx") #define put_user(x, ptr) \ __put_user_check((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr))) -- cgit v1.2.2 From 0ada3164031162b4e1b7ff6b36ba8cc80ff7fe96 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Tue, 24 Jun 2008 16:44:39 -0300 Subject: x86: pass argument to putuser_64 functions in ax register. This is consistent with i386 usage. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess_64.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-x86/uaccess_64.h b/include/asm-x86/uaccess_64.h index 21fda9ebee13..f822a36cc1c0 100644 --- a/include/asm-x86/uaccess_64.h +++ b/include/asm-x86/uaccess_64.h @@ -130,7 +130,7 @@ extern void __put_user_bad(void); #define __put_user_x(size, ret, x, ptr) \ asm volatile("call __put_user_" #size \ :"=a" (ret) \ - :"c" (ptr),"d" (x) \ + :"c" (ptr),"a" (x) \ :"ebx") #define put_user(x, ptr) \ -- cgit v1.2.2 From 2528de431ddb200653d1dc6ca90074bad9520f09 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Tue, 24 Jun 2008 17:36:31 -0300 Subject: x86: use macros from asm.h. In putuser_32.S and putuser_64.S, replace things like .quad, .long, and explicit references to [r|e]ax for the apropriate macros in asm/asm.h. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/asm.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/asm-x86/asm.h b/include/asm-x86/asm.h index 57750a95685d..97220321f39d 100644 --- a/include/asm-x86/asm.h +++ b/include/asm-x86/asm.h @@ -28,6 +28,8 @@ #define _ASM_SUB __ASM_SIZE(sub) #define _ASM_XADD __ASM_SIZE(xadd) #define _ASM_AX __ASM_REG(ax) +#define _ASM_BX __ASM_REG(bx) +#define _ASM_CX __ASM_REG(cx) #define _ASM_DX __ASM_REG(dx) /* Exception table entry */ -- cgit v1.2.2 From 53938a68a2f971058bc53aaa8c70f9f24f684cdc Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Wed, 25 Jun 2008 10:14:13 -0300 Subject: x86: commonize __range_not_ok. For i386, __range_not_ok is a better name than __range_ok, since it returns 0 when it is in fact okay. Other than that, both versions does not need the word size specifiers, and we remove them. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess_32.h | 6 +++--- include/asm-x86/uaccess_64.h | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/asm-x86/uaccess_32.h b/include/asm-x86/uaccess_32.h index f8abc12a77c2..8d3f02d3562c 100644 --- a/include/asm-x86/uaccess_32.h +++ b/include/asm-x86/uaccess_32.h @@ -56,11 +56,11 @@ extern struct movsl_mask { * * This needs 33-bit arithmetic. We have a carry... */ -#define __range_ok(addr, size) \ +#define __range_not_ok(addr, size) \ ({ \ unsigned long flag, roksum; \ __chk_user_ptr(addr); \ - asm("addl %3,%1 ; sbbl %0,%0; cmpl %1,%4; sbbl $0,%0" \ + asm("add %3,%1 ; sbb %0,%0; cmp %1,%4; sbb $0,%0" \ :"=&r" (flag), "=r" (roksum) \ :"1" (addr), "g" ((int)(size)), \ "rm" (current_thread_info()->addr_limit.seg)); \ @@ -86,7 +86,7 @@ extern struct movsl_mask { * checks that the pointer is in the user space range - after calling * this function, memory access functions may still return -EFAULT. */ -#define access_ok(type, addr, size) (likely(__range_ok(addr, size) == 0)) +#define access_ok(type, addr, size) (likely(__range_not_ok(addr, size) == 0)) /* * The exception table consists of pairs of addresses: the first is the diff --git a/include/asm-x86/uaccess_64.h b/include/asm-x86/uaccess_64.h index f822a36cc1c0..012cba3972d7 100644 --- a/include/asm-x86/uaccess_64.h +++ b/include/asm-x86/uaccess_64.h @@ -41,8 +41,7 @@ ({ \ unsigned long flag, roksum; \ __chk_user_ptr(addr); \ - asm("# range_ok\n\r" \ - "addq %3,%1 ; sbbq %0,%0 ; cmpq %1,%4 ; sbbq $0,%0" \ + asm("add %3,%1 ; sbb %0,%0 ; cmp %1,%4 ; sbb $0,%0" \ : "=&r" (flag), "=r" (roksum) \ : "1" (addr), "g" ((long)(size)), \ "g" (current_thread_info()->addr_limit.seg)); \ -- cgit v1.2.2 From c28b95d9bb7da0c3be22826c56a05899e21e5ece Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Mon, 30 Jun 2008 17:07:51 -0300 Subject: x86: change asm constraint. Our integration efforts broke a build with this function being used with i386. Reason is "g" can put the operand in an imm32, which according to The Book (tm), is invalid as the second operand. This is actually a bug in x86_64 too, since the x86_64 instruction set reference does not list it as valid. We probably didn't trigger this before due to the ammount of registers available for 64-bit platforms. But that's just my guess. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess_64.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-x86/uaccess_64.h b/include/asm-x86/uaccess_64.h index 012cba3972d7..dc6dde058381 100644 --- a/include/asm-x86/uaccess_64.h +++ b/include/asm-x86/uaccess_64.h @@ -44,7 +44,7 @@ asm("add %3,%1 ; sbb %0,%0 ; cmp %1,%4 ; sbb $0,%0" \ : "=&r" (flag), "=r" (roksum) \ : "1" (addr), "g" ((long)(size)), \ - "g" (current_thread_info()->addr_limit.seg)); \ + "rm" (current_thread_info()->addr_limit.seg)); \ flag; \ }) -- cgit v1.2.2 From 8b0a8aaf05325a1a96f53b45708f77599da35161 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Mon, 30 Jun 2008 17:34:39 -0300 Subject: x86: introduce likely in macro. Put the likely hint in access_ok. Just for bisectability. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess_64.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-x86/uaccess_64.h b/include/asm-x86/uaccess_64.h index dc6dde058381..0077dbe9359e 100644 --- a/include/asm-x86/uaccess_64.h +++ b/include/asm-x86/uaccess_64.h @@ -48,7 +48,7 @@ flag; \ }) -#define access_ok(type, addr, size) (__range_not_ok(addr, size) == 0) +#define access_ok(type, addr, size) (likely(__range_not_ok(addr, size) == 0)) /* * The exception table consists of pairs of addresses: the first is the -- cgit v1.2.2 From 1dc186e82c1ab476ef83080adca43a70969b01cd Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Mon, 30 Jun 2008 17:37:08 -0300 Subject: x86: use long instead of int. Do not refer to the processor word-size with int, as it won't work with x86_64. Use long instead. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess_32.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-x86/uaccess_32.h b/include/asm-x86/uaccess_32.h index 8d3f02d3562c..eed8d9422b4d 100644 --- a/include/asm-x86/uaccess_32.h +++ b/include/asm-x86/uaccess_32.h @@ -62,7 +62,7 @@ extern struct movsl_mask { __chk_user_ptr(addr); \ asm("add %3,%1 ; sbb %0,%0; cmp %1,%4; sbb $0,%0" \ :"=&r" (flag), "=r" (roksum) \ - :"1" (addr), "g" ((int)(size)), \ + :"1" (addr), "g" ((long)(size)), \ "rm" (current_thread_info()->addr_limit.seg)); \ flag; \ }) -- cgit v1.2.2 From be9d06bfd48934fbd56ccb7476eabccfa31b4afe Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Fri, 13 Jun 2008 21:01:46 -0300 Subject: x86: use something common for both architectures. Using explicit hexa (0xFFFFFFUL) introduces an unnecessary difference between i386 and x86_64 because of the size of their long. Use -1UL instead. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess_32.h | 2 +- include/asm-x86/uaccess_64.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/asm-x86/uaccess_32.h b/include/asm-x86/uaccess_32.h index eed8d9422b4d..2676b48ac0fa 100644 --- a/include/asm-x86/uaccess_32.h +++ b/include/asm-x86/uaccess_32.h @@ -25,7 +25,7 @@ #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) -#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFFUL) +#define KERNEL_DS MAKE_MM_SEG(-1UL) #define USER_DS MAKE_MM_SEG(PAGE_OFFSET) #define get_ds() (KERNEL_DS) diff --git a/include/asm-x86/uaccess_64.h b/include/asm-x86/uaccess_64.h index 0077dbe9359e..3a81775136c8 100644 --- a/include/asm-x86/uaccess_64.h +++ b/include/asm-x86/uaccess_64.h @@ -22,7 +22,7 @@ #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) -#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFFFFFFFFFFUL) +#define KERNEL_DS MAKE_MM_SEG(-1UL) #define USER_DS MAKE_MM_SEG(PAGE_OFFSET) #define get_ds() (KERNEL_DS) -- cgit v1.2.2 From ca23386216b9d4fc3bb211101205077d2b2916ae Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Fri, 13 Jun 2008 14:39:25 -0300 Subject: x86: merge common parts of uaccess. Common parts of uaccess_32.h and uaccess_64.h are put in uaccess.h. Bits in uaccess_32.h and uaccess_64.h that come to this file are equal except for comments and whitespaces differences. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess.h | 124 +++++++++++++++++++++++++++++++++++++++++++ include/asm-x86/uaccess_32.h | 110 -------------------------------------- include/asm-x86/uaccess_64.h | 83 ----------------------------- 3 files changed, 124 insertions(+), 193 deletions(-) (limited to 'include') diff --git a/include/asm-x86/uaccess.h b/include/asm-x86/uaccess.h index 9fefd2947e78..2fc30c2a8a98 100644 --- a/include/asm-x86/uaccess.h +++ b/include/asm-x86/uaccess.h @@ -1,5 +1,129 @@ +#ifndef _ASM_UACCES_H_ +#define _ASM_UACCES_H_ +/* + * User space memory access functions + */ +#include +#include +#include +#include +#include +#include +#include + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +/* + * The fs value determines whether argument validity checking should be + * performed or not. If get_fs() == USER_DS, checking is performed, with + * get_fs() == KERNEL_DS, checking is bypassed. + * + * For historical reasons, these macros are grossly misnamed. + */ + +#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) + +#define KERNEL_DS MAKE_MM_SEG(-1UL) +#define USER_DS MAKE_MM_SEG(PAGE_OFFSET) + +#define get_ds() (KERNEL_DS) +#define get_fs() (current_thread_info()->addr_limit) +#define set_fs(x) (current_thread_info()->addr_limit = (x)) + +#define segment_eq(a, b) ((a).seg == (b).seg) + +/* + * Test whether a block of memory is a valid user space address. + * Returns 0 if the range is valid, nonzero otherwise. + * + * This is equivalent to the following test: + * (u33)addr + (u33)size >= (u33)current->addr_limit.seg (u65 for x86_64) + * + * This needs 33-bit (65-bit for x86_64) arithmetic. We have a carry... + */ + +#define __range_not_ok(addr, size) \ +({ \ + unsigned long flag, roksum; \ + __chk_user_ptr(addr); \ + asm("add %3,%1 ; sbb %0,%0 ; cmp %1,%4 ; sbb $0,%0" \ + : "=&r" (flag), "=r" (roksum) \ + : "1" (addr), "g" ((long)(size)), \ + "rm" (current_thread_info()->addr_limit.seg)); \ + flag; \ +}) + +/** + * access_ok: - Checks if a user space pointer is valid + * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE. Note that + * %VERIFY_WRITE is a superset of %VERIFY_READ - if it is safe + * to write to a block, it is always safe to read from it. + * @addr: User space pointer to start of block to check + * @size: Size of block to check + * + * Context: User context only. This function may sleep. + * + * Checks if a pointer to a block of memory in user space is valid. + * + * Returns true (nonzero) if the memory block may be valid, false (zero) + * if it is definitely invalid. + * + * Note that, depending on architecture, this function probably just + * checks that the pointer is in the user space range - after calling + * this function, memory access functions may still return -EFAULT. + */ +#define access_ok(type, addr, size) (likely(__range_not_ok(addr, size) == 0)) + +/* + * The exception table consists of pairs of addresses: the first is the + * address of an instruction that is allowed to fault, and the second is + * the address at which the program should continue. No registers are + * modified, so it is entirely up to the continuation code to figure out + * what to do. + * + * All the routines below use bits of fixup code that are out of line + * with the main instruction path. This means when everything is well, + * we don't even have to jump over them. Further, they do not intrude + * on our cache or tlb entries. + */ + +struct exception_table_entry { + unsigned long insn, fixup; +}; + +extern int fixup_exception(struct pt_regs *regs); + +/* + * These are the main single-value transfer routines. They automatically + * use the right size if we just have the right pointer type. + * + * This gets kind of ugly. We want to return _two_ values in "get_user()" + * and yet we don't want to do any pointers, because that is too much + * of a performance impact. Thus we have a few rather ugly macros here, + * and hide all the ugliness from the user. + * + * The "__xxx" versions of the user access functions are versions that + * do not verify the address space, that must have been done previously + * with a separate "access_ok()" call (this is used when we do multiple + * accesses to the same area of user memory). + */ + +extern int __get_user_1(void); +extern int __get_user_2(void); +extern int __get_user_4(void); +extern int __get_user_8(void); +extern int __get_user_bad(void); + +#define __get_user_x(size, ret, x, ptr) \ + asm volatile("call __get_user_" #size \ + : "=a" (ret),"=d" (x) \ + : "0" (ptr)) \ + #ifdef CONFIG_X86_32 # include "uaccess_32.h" #else # include "uaccess_64.h" #endif + +#endif diff --git a/include/asm-x86/uaccess_32.h b/include/asm-x86/uaccess_32.h index 2676b48ac0fa..92ad19e70989 100644 --- a/include/asm-x86/uaccess_32.h +++ b/include/asm-x86/uaccess_32.h @@ -11,29 +11,6 @@ #include #include -#define VERIFY_READ 0 -#define VERIFY_WRITE 1 - -/* - * The fs value determines whether argument validity checking should be - * performed or not. If get_fs() == USER_DS, checking is performed, with - * get_fs() == KERNEL_DS, checking is bypassed. - * - * For historical reasons, these macros are grossly misnamed. - */ - -#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) - - -#define KERNEL_DS MAKE_MM_SEG(-1UL) -#define USER_DS MAKE_MM_SEG(PAGE_OFFSET) - -#define get_ds() (KERNEL_DS) -#define get_fs() (current_thread_info()->addr_limit) -#define set_fs(x) (current_thread_info()->addr_limit = (x)) - -#define segment_eq(a, b) ((a).seg == (b).seg) - /* * movsl can be slow when source and dest are not both 8-byte aligned */ @@ -47,91 +24,6 @@ extern struct movsl_mask { ((unsigned long __force)(addr) < \ (current_thread_info()->addr_limit.seg)) -/* - * Test whether a block of memory is a valid user space address. - * Returns 0 if the range is valid, nonzero otherwise. - * - * This is equivalent to the following test: - * (u33)addr + (u33)size >= (u33)current->addr_limit.seg - * - * This needs 33-bit arithmetic. We have a carry... - */ -#define __range_not_ok(addr, size) \ -({ \ - unsigned long flag, roksum; \ - __chk_user_ptr(addr); \ - asm("add %3,%1 ; sbb %0,%0; cmp %1,%4; sbb $0,%0" \ - :"=&r" (flag), "=r" (roksum) \ - :"1" (addr), "g" ((long)(size)), \ - "rm" (current_thread_info()->addr_limit.seg)); \ - flag; \ -}) - -/** - * access_ok: - Checks if a user space pointer is valid - * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE. Note that - * %VERIFY_WRITE is a superset of %VERIFY_READ - if it is safe - * to write to a block, it is always safe to read from it. - * @addr: User space pointer to start of block to check - * @size: Size of block to check - * - * Context: User context only. This function may sleep. - * - * Checks if a pointer to a block of memory in user space is valid. - * - * Returns true (nonzero) if the memory block may be valid, false (zero) - * if it is definitely invalid. - * - * Note that, depending on architecture, this function probably just - * checks that the pointer is in the user space range - after calling - * this function, memory access functions may still return -EFAULT. - */ -#define access_ok(type, addr, size) (likely(__range_not_ok(addr, size) == 0)) - -/* - * The exception table consists of pairs of addresses: the first is the - * address of an instruction that is allowed to fault, and the second is - * the address at which the program should continue. No registers are - * modified, so it is entirely up to the continuation code to figure out - * what to do. - * - * All the routines below use bits of fixup code that are out of line - * with the main instruction path. This means when everything is well, - * we don't even have to jump over them. Further, they do not intrude - * on our cache or tlb entries. - */ - -struct exception_table_entry { - unsigned long insn, fixup; -}; - -extern int fixup_exception(struct pt_regs *regs); - -/* - * These are the main single-value transfer routines. They automatically - * use the right size if we just have the right pointer type. - * - * This gets kind of ugly. We want to return _two_ values in "get_user()" - * and yet we don't want to do any pointers, because that is too much - * of a performance impact. Thus we have a few rather ugly macros here, - * and hide all the ugliness from the user. - * - * The "__xxx" versions of the user access functions are versions that - * do not verify the address space, that must have been done previously - * with a separate "access_ok()" call (this is used when we do multiple - * accesses to the same area of user memory). - */ - -extern void __get_user_1(void); -extern void __get_user_2(void); -extern void __get_user_4(void); - -#define __get_user_x(size, ret, x, ptr) \ - asm volatile("call __get_user_" #size \ - :"=a" (ret),"=d" (x) \ - :"0" (ptr)) - - /* Careful: we have to cast the result to the type of the pointer * for sign reasons */ @@ -386,8 +278,6 @@ struct __large_struct { unsigned long buf[100]; }; __gu_err; \ }) -extern long __get_user_bad(void); - #define __get_user_size(x, ptr, size, retval, errret) \ do { \ retval = 0; \ diff --git a/include/asm-x86/uaccess_64.h b/include/asm-x86/uaccess_64.h index 3a81775136c8..243dbb467f3a 100644 --- a/include/asm-x86/uaccess_64.h +++ b/include/asm-x86/uaccess_64.h @@ -9,88 +9,11 @@ #include #include -#define VERIFY_READ 0 -#define VERIFY_WRITE 1 - -/* - * The fs value determines whether argument validity checking should be - * performed or not. If get_fs() == USER_DS, checking is performed, with - * get_fs() == KERNEL_DS, checking is bypassed. - * - * For historical reasons, these macros are grossly misnamed. - */ - -#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) - -#define KERNEL_DS MAKE_MM_SEG(-1UL) -#define USER_DS MAKE_MM_SEG(PAGE_OFFSET) - -#define get_ds() (KERNEL_DS) -#define get_fs() (current_thread_info()->addr_limit) -#define set_fs(x) (current_thread_info()->addr_limit = (x)) - -#define segment_eq(a, b) ((a).seg == (b).seg) - #define __addr_ok(addr) (!((unsigned long)(addr) & \ (current_thread_info()->addr_limit.seg))) -/* - * Uhhuh, this needs 65-bit arithmetic. We have a carry.. - */ -#define __range_not_ok(addr, size) \ -({ \ - unsigned long flag, roksum; \ - __chk_user_ptr(addr); \ - asm("add %3,%1 ; sbb %0,%0 ; cmp %1,%4 ; sbb $0,%0" \ - : "=&r" (flag), "=r" (roksum) \ - : "1" (addr), "g" ((long)(size)), \ - "rm" (current_thread_info()->addr_limit.seg)); \ - flag; \ -}) - -#define access_ok(type, addr, size) (likely(__range_not_ok(addr, size) == 0)) - -/* - * The exception table consists of pairs of addresses: the first is the - * address of an instruction that is allowed to fault, and the second is - * the address at which the program should continue. No registers are - * modified, so it is entirely up to the continuation code to figure out - * what to do. - * - * All the routines below use bits of fixup code that are out of line - * with the main instruction path. This means when everything is well, - * we don't even have to jump over them. Further, they do not intrude - * on our cache or tlb entries. - */ - -struct exception_table_entry { - unsigned long insn, fixup; -}; - -extern int fixup_exception(struct pt_regs *regs); - #define ARCH_HAS_SEARCH_EXTABLE -/* - * These are the main single-value transfer routines. They automatically - * use the right size if we just have the right pointer type. - * - * This gets kind of ugly. We want to return _two_ values in "get_user()" - * and yet we don't want to do any pointers, because that is too much - * of a performance impact. Thus we have a few rather ugly macros here, - * and hide all the ugliness from the user. - * - * The "__xxx" versions of the user access functions are versions that - * do not verify the address space, that must have been done previously - * with a separate "access_ok()" call (this is used when we do multiple - * accesses to the same area of user memory). - */ - -#define __get_user_x(size, ret, x, ptr) \ - asm volatile("call __get_user_" #size \ - : "=a" (ret),"=d" (x) \ - : "0" (ptr)) \ - /* Careful: we have to cast the result to the type of the pointer * for sign reasons */ @@ -226,12 +149,6 @@ struct __large_struct { unsigned long buf[100]; }; __gu_err; \ }) -extern int __get_user_1(void); -extern int __get_user_2(void); -extern int __get_user_4(void); -extern int __get_user_8(void); -extern int __get_user_bad(void); - #define __get_user_size(x, ptr, size, retval) \ do { \ retval = 0; \ -- cgit v1.2.2 From 865e5b76505cdade261773bde32f785b3ce579f1 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Wed, 25 Jun 2008 11:05:11 -0300 Subject: x86: merge getuser. Merge versions of getuser from uaccess_32.h and uaccess_64.h into uaccess.h. There is a part which is 64-bit only (for now), and for that, we use a __get_user_8 macro. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess.h | 55 ++++++++++++++++++++++++++++++++++++++++++++ include/asm-x86/uaccess_32.h | 43 ---------------------------------- include/asm-x86/uaccess_64.h | 29 ----------------------- 3 files changed, 55 insertions(+), 72 deletions(-) (limited to 'include') diff --git a/include/asm-x86/uaccess.h b/include/asm-x86/uaccess.h index 2fc30c2a8a98..8cb580c0b411 100644 --- a/include/asm-x86/uaccess.h +++ b/include/asm-x86/uaccess.h @@ -120,6 +120,61 @@ extern int __get_user_bad(void); : "=a" (ret),"=d" (x) \ : "0" (ptr)) \ +/* Careful: we have to cast the result to the type of the pointer + * for sign reasons */ + +/** + * get_user: - Get a simple variable from user space. + * @x: Variable to store result. + * @ptr: Source address, in user space. + * + * Context: User context only. This function may sleep. + * + * This macro copies a single simple variable from user space to kernel + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and the result of + * dereferencing @ptr must be assignable to @x without a cast. + * + * Returns zero on success, or -EFAULT on error. + * On error, the variable @x is set to zero. + */ +#ifdef CONFIG_X86_32 +#define __get_user_8(__ret_gu, __val_gu, ptr) \ + __get_user_x(X, __ret_gu, __val_gu, ptr) +#else +#define __get_user_8(__ret_gu, __val_gu, ptr) \ + __get_user_x(8, __ret_gu, __val_gu, ptr) +#endif + +#define get_user(x, ptr) \ +({ \ + int __ret_gu; \ + unsigned long __val_gu; \ + __chk_user_ptr(ptr); \ + switch (sizeof(*(ptr))) { \ + case 1: \ + __get_user_x(1, __ret_gu, __val_gu, ptr); \ + break; \ + case 2: \ + __get_user_x(2, __ret_gu, __val_gu, ptr); \ + break; \ + case 4: \ + __get_user_x(4, __ret_gu, __val_gu, ptr); \ + break; \ + case 8: \ + __get_user_8(__ret_gu, __val_gu, ptr); \ + break; \ + default: \ + __get_user_x(X, __ret_gu, __val_gu, ptr); \ + break; \ + } \ + (x) = (__typeof__(*(ptr)))__val_gu; \ + __ret_gu; \ +}) + + #ifdef CONFIG_X86_32 # include "uaccess_32.h" #else diff --git a/include/asm-x86/uaccess_32.h b/include/asm-x86/uaccess_32.h index 92ad19e70989..3cc323694438 100644 --- a/include/asm-x86/uaccess_32.h +++ b/include/asm-x86/uaccess_32.h @@ -24,49 +24,6 @@ extern struct movsl_mask { ((unsigned long __force)(addr) < \ (current_thread_info()->addr_limit.seg)) -/* Careful: we have to cast the result to the type of the pointer - * for sign reasons */ - -/** - * get_user: - Get a simple variable from user space. - * @x: Variable to store result. - * @ptr: Source address, in user space. - * - * Context: User context only. This function may sleep. - * - * This macro copies a single simple variable from user space to kernel - * space. It supports simple types like char and int, but not larger - * data types like structures or arrays. - * - * @ptr must have pointer-to-simple-variable type, and the result of - * dereferencing @ptr must be assignable to @x without a cast. - * - * Returns zero on success, or -EFAULT on error. - * On error, the variable @x is set to zero. - */ -#define get_user(x, ptr) \ -({ \ - int __ret_gu; \ - unsigned long __val_gu; \ - __chk_user_ptr(ptr); \ - switch (sizeof(*(ptr))) { \ - case 1: \ - __get_user_x(1, __ret_gu, __val_gu, ptr); \ - break; \ - case 2: \ - __get_user_x(2, __ret_gu, __val_gu, ptr); \ - break; \ - case 4: \ - __get_user_x(4, __ret_gu, __val_gu, ptr); \ - break; \ - default: \ - __get_user_x(X, __ret_gu, __val_gu, ptr); \ - break; \ - } \ - (x) = (__typeof__(*(ptr)))__val_gu; \ - __ret_gu; \ -}) - extern void __put_user_bad(void); /* diff --git a/include/asm-x86/uaccess_64.h b/include/asm-x86/uaccess_64.h index 243dbb467f3a..4a44b906e4c3 100644 --- a/include/asm-x86/uaccess_64.h +++ b/include/asm-x86/uaccess_64.h @@ -14,35 +14,6 @@ #define ARCH_HAS_SEARCH_EXTABLE -/* Careful: we have to cast the result to the type of the pointer - * for sign reasons */ - -#define get_user(x, ptr) \ -({ \ - unsigned long __val_gu; \ - int __ret_gu; \ - __chk_user_ptr(ptr); \ - switch (sizeof(*(ptr))) { \ - case 1: \ - __get_user_x(1, __ret_gu, __val_gu, ptr); \ - break; \ - case 2: \ - __get_user_x(2, __ret_gu, __val_gu, ptr); \ - break; \ - case 4: \ - __get_user_x(4, __ret_gu, __val_gu, ptr); \ - break; \ - case 8: \ - __get_user_x(8, __ret_gu, __val_gu, ptr); \ - break; \ - default: \ - __get_user_bad(); \ - break; \ - } \ - (x) = (__force typeof(*(ptr)))__val_gu; \ - __ret_gu; \ -}) - extern void __put_user_1(void); extern void __put_user_2(void); extern void __put_user_4(void); -- cgit v1.2.2 From 002ca1690c3d0a495e6aedd608281aeb01ce6385 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Wed, 25 Jun 2008 11:08:51 -0300 Subject: x86: move __addr_ok to uaccess.h. Take it out of uaccess_32.h. Since it seems that no users of the x86_64 exists, we simply pick the i386 version. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess.h | 4 ++++ include/asm-x86/uaccess_32.h | 4 ---- include/asm-x86/uaccess_64.h | 3 --- 3 files changed, 4 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/asm-x86/uaccess.h b/include/asm-x86/uaccess.h index 8cb580c0b411..8a1e45fdc980 100644 --- a/include/asm-x86/uaccess.h +++ b/include/asm-x86/uaccess.h @@ -33,6 +33,10 @@ #define segment_eq(a, b) ((a).seg == (b).seg) +#define __addr_ok(addr) \ + ((unsigned long __force)(addr) < \ + (current_thread_info()->addr_limit.seg)) + /* * Test whether a block of memory is a valid user space address. * Returns 0 if the range is valid, nonzero otherwise. diff --git a/include/asm-x86/uaccess_32.h b/include/asm-x86/uaccess_32.h index 3cc323694438..87b1aede9d4b 100644 --- a/include/asm-x86/uaccess_32.h +++ b/include/asm-x86/uaccess_32.h @@ -20,10 +20,6 @@ extern struct movsl_mask { } ____cacheline_aligned_in_smp movsl_mask; #endif -#define __addr_ok(addr) \ - ((unsigned long __force)(addr) < \ - (current_thread_info()->addr_limit.seg)) - extern void __put_user_bad(void); /* diff --git a/include/asm-x86/uaccess_64.h b/include/asm-x86/uaccess_64.h index 4a44b906e4c3..81308763a4c1 100644 --- a/include/asm-x86/uaccess_64.h +++ b/include/asm-x86/uaccess_64.h @@ -9,9 +9,6 @@ #include #include -#define __addr_ok(addr) (!((unsigned long)(addr) & \ - (current_thread_info()->addr_limit.seg))) - #define ARCH_HAS_SEARCH_EXTABLE extern void __put_user_1(void); -- cgit v1.2.2 From 5e322163b19735fbef3e294c297d38e0d2ba8f7e Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Wed, 25 Jun 2008 11:35:06 -0300 Subject: x86: use k modifier for 4-byte access. Do it in a separate patch for bisectability. Goal is to have put_user_size integrated. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess_32.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/asm-x86/uaccess_32.h b/include/asm-x86/uaccess_32.h index 87b1aede9d4b..4c47a5ba65e3 100644 --- a/include/asm-x86/uaccess_32.h +++ b/include/asm-x86/uaccess_32.h @@ -180,7 +180,7 @@ do { \ __put_user_asm(x, ptr, retval, "w", "w", "ir", errret); \ break; \ case 4: \ - __put_user_asm(x, ptr, retval, "l", "", "ir", errret); \ + __put_user_asm(x, ptr, retval, "l", "k", "ir", errret);\ break; \ case 8: \ __put_user_u64((__typeof__(*ptr))(x), ptr, retval); \ -- cgit v1.2.2 From d42e6af613375be7a9a431628ecd742e87230554 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Wed, 25 Jun 2008 12:00:44 -0300 Subject: x86: don't always use EFAULT on __put_user_size. Let the user of the macro specify the desired return. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess_64.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/asm-x86/uaccess_64.h b/include/asm-x86/uaccess_64.h index 81308763a4c1..6532d638d5a3 100644 --- a/include/asm-x86/uaccess_64.h +++ b/include/asm-x86/uaccess_64.h @@ -37,7 +37,7 @@ extern void __put_user_bad(void); #define __put_user_nocheck(x, ptr, size) \ ({ \ int __pu_err; \ - __put_user_size((x), (ptr), (size), __pu_err); \ + __put_user_size((x), (ptr), (size), __pu_err, -EFAULT); \ __pu_err; \ }) @@ -65,22 +65,22 @@ extern void __put_user_bad(void); __pu_err; \ }) -#define __put_user_size(x, ptr, size, retval) \ +#define __put_user_size(x, ptr, size, retval, errret) \ do { \ retval = 0; \ __chk_user_ptr(ptr); \ switch (size) { \ case 1: \ - __put_user_asm(x, ptr, retval, "b", "b", "iq", -EFAULT);\ + __put_user_asm(x, ptr, retval, "b", "b", "iq", errret);\ break; \ case 2: \ - __put_user_asm(x, ptr, retval, "w", "w", "ir", -EFAULT);\ + __put_user_asm(x, ptr, retval, "w", "w", "ir", errret);\ break; \ case 4: \ - __put_user_asm(x, ptr, retval, "l", "k", "ir", -EFAULT);\ + __put_user_asm(x, ptr, retval, "l", "k", "ir", errret);\ break; \ case 8: \ - __put_user_asm(x, ptr, retval, "q", "", "Zr", -EFAULT); \ + __put_user_asm(x, ptr, retval, "q", "", "Zr", errret); \ break; \ default: \ __put_user_bad(); \ -- cgit v1.2.2 From dc70ddf4098de043ac52f623c7573a11f2ae3d09 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Wed, 25 Jun 2008 11:48:29 -0300 Subject: x86: merge __put_user_asm and its user. Move both __put_user_asm and __put_user_size to uaccess.h. i386 already had a special function for 64-bit access, so for x86_64, we just define a macro with the same name. Note that for X86_64, CONFIG_X86_WP_WORKS_OK will always be defined, so the #else part will never be even compiled in. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess.h | 84 ++++++++++++++++++++++++++++++++++++++++++++ include/asm-x86/uaccess_32.h | 77 ---------------------------------------- include/asm-x86/uaccess_64.h | 51 --------------------------- 3 files changed, 84 insertions(+), 128 deletions(-) (limited to 'include') diff --git a/include/asm-x86/uaccess.h b/include/asm-x86/uaccess.h index 8a1e45fdc980..bcda5d075921 100644 --- a/include/asm-x86/uaccess.h +++ b/include/asm-x86/uaccess.h @@ -178,6 +178,90 @@ extern int __get_user_bad(void); __ret_gu; \ }) +#ifdef CONFIG_X86_32 +#define __put_user_u64(x, addr, err) \ + asm volatile("1: movl %%eax,0(%2)\n" \ + "2: movl %%edx,4(%2)\n" \ + "3:\n" \ + ".section .fixup,\"ax\"\n" \ + "4: movl %3,%0\n" \ + " jmp 3b\n" \ + ".previous\n" \ + _ASM_EXTABLE(1b, 4b) \ + _ASM_EXTABLE(2b, 4b) \ + : "=r" (err) \ + : "A" (x), "r" (addr), "i" (-EFAULT), "0" (err)) +#else +#define __put_user_u64(x, ptr, retval) \ + __put_user_asm(x, ptr, retval, "q", "", "Zr", -EFAULT) +#endif + +#ifdef CONFIG_X86_WP_WORKS_OK + +#define __put_user_size(x, ptr, size, retval, errret) \ +do { \ + retval = 0; \ + __chk_user_ptr(ptr); \ + switch (size) { \ + case 1: \ + __put_user_asm(x, ptr, retval, "b", "b", "iq", errret); \ + break; \ + case 2: \ + __put_user_asm(x, ptr, retval, "w", "w", "ir", errret); \ + break; \ + case 4: \ + __put_user_asm(x, ptr, retval, "l", "k", "ir", errret);\ + break; \ + case 8: \ + __put_user_u64((__typeof__(*ptr))(x), ptr, retval); \ + break; \ + default: \ + __put_user_bad(); \ + } \ +} while (0) + +#else + +#define __put_user_size(x, ptr, size, retval, errret) \ +do { \ + __typeof__(*(ptr))__pus_tmp = x; \ + retval = 0; \ + \ + if (unlikely(__copy_to_user_ll(ptr, &__pus_tmp, size) != 0)) \ + retval = errret; \ +} while (0) + +#endif + +#define __put_user_nocheck(x, ptr, size) \ +({ \ + long __pu_err; \ + __put_user_size((x), (ptr), (size), __pu_err, -EFAULT); \ + __pu_err; \ +}) + + + +/* FIXME: this hack is definitely wrong -AK */ +struct __large_struct { unsigned long buf[100]; }; +#define __m(x) (*(struct __large_struct __user *)(x)) + +/* + * Tell gcc we read from memory instead of writing: this is because + * we do not write to any memory gcc knows about, so there are no + * aliasing issues. + */ +#define __put_user_asm(x, addr, err, itype, rtype, ltype, errret) \ + asm volatile("1: mov"itype" %"rtype"1,%2\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: mov %3,%0\n" \ + " jmp 2b\n" \ + ".previous\n" \ + _ASM_EXTABLE(1b, 3b) \ + : "=r"(err) \ + : ltype(x), "m" (__m(addr)), "i" (errret), "0" (err)) + #ifdef CONFIG_X86_32 # include "uaccess_32.h" diff --git a/include/asm-x86/uaccess_32.h b/include/asm-x86/uaccess_32.h index 4c47a5ba65e3..fab755781b9b 100644 --- a/include/asm-x86/uaccess_32.h +++ b/include/asm-x86/uaccess_32.h @@ -145,83 +145,6 @@ extern void __put_user_8(void); #define __put_user(x, ptr) \ __put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr))) -#define __put_user_nocheck(x, ptr, size) \ -({ \ - long __pu_err; \ - __put_user_size((x), (ptr), (size), __pu_err, -EFAULT); \ - __pu_err; \ -}) - - -#define __put_user_u64(x, addr, err) \ - asm volatile("1: movl %%eax,0(%2)\n" \ - "2: movl %%edx,4(%2)\n" \ - "3:\n" \ - ".section .fixup,\"ax\"\n" \ - "4: movl %3,%0\n" \ - " jmp 3b\n" \ - ".previous\n" \ - _ASM_EXTABLE(1b, 4b) \ - _ASM_EXTABLE(2b, 4b) \ - : "=r" (err) \ - : "A" (x), "r" (addr), "i" (-EFAULT), "0" (err)) - -#ifdef CONFIG_X86_WP_WORKS_OK - -#define __put_user_size(x, ptr, size, retval, errret) \ -do { \ - retval = 0; \ - __chk_user_ptr(ptr); \ - switch (size) { \ - case 1: \ - __put_user_asm(x, ptr, retval, "b", "b", "iq", errret); \ - break; \ - case 2: \ - __put_user_asm(x, ptr, retval, "w", "w", "ir", errret); \ - break; \ - case 4: \ - __put_user_asm(x, ptr, retval, "l", "k", "ir", errret);\ - break; \ - case 8: \ - __put_user_u64((__typeof__(*ptr))(x), ptr, retval); \ - break; \ - default: \ - __put_user_bad(); \ - } \ -} while (0) - -#else - -#define __put_user_size(x, ptr, size, retval, errret) \ -do { \ - __typeof__(*(ptr))__pus_tmp = x; \ - retval = 0; \ - \ - if (unlikely(__copy_to_user_ll(ptr, &__pus_tmp, size) != 0)) \ - retval = errret; \ -} while (0) - -#endif -struct __large_struct { unsigned long buf[100]; }; -#define __m(x) (*(struct __large_struct __user *)(x)) - -/* - * Tell gcc we read from memory instead of writing: this is because - * we do not write to any memory gcc knows about, so there are no - * aliasing issues. - */ -#define __put_user_asm(x, addr, err, itype, rtype, ltype, errret) \ - asm volatile("1: mov"itype" %"rtype"1,%2\n" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: movl %3,%0\n" \ - " jmp 2b\n" \ - ".previous\n" \ - _ASM_EXTABLE(1b, 3b) \ - : "=r"(err) \ - : ltype (x), "m" (__m(addr)), "i" (errret), "0" (err)) - - #define __get_user_nocheck(x, ptr, size) \ ({ \ long __gu_err; \ diff --git a/include/asm-x86/uaccess_64.h b/include/asm-x86/uaccess_64.h index 6532d638d5a3..42c01aa70e72 100644 --- a/include/asm-x86/uaccess_64.h +++ b/include/asm-x86/uaccess_64.h @@ -34,14 +34,6 @@ extern void __put_user_bad(void); #define __get_user_unaligned __get_user #define __put_user_unaligned __put_user -#define __put_user_nocheck(x, ptr, size) \ -({ \ - int __pu_err; \ - __put_user_size((x), (ptr), (size), __pu_err, -EFAULT); \ - __pu_err; \ -}) - - #define __put_user_check(x, ptr, size) \ ({ \ int __pu_err; \ @@ -65,49 +57,6 @@ extern void __put_user_bad(void); __pu_err; \ }) -#define __put_user_size(x, ptr, size, retval, errret) \ -do { \ - retval = 0; \ - __chk_user_ptr(ptr); \ - switch (size) { \ - case 1: \ - __put_user_asm(x, ptr, retval, "b", "b", "iq", errret);\ - break; \ - case 2: \ - __put_user_asm(x, ptr, retval, "w", "w", "ir", errret);\ - break; \ - case 4: \ - __put_user_asm(x, ptr, retval, "l", "k", "ir", errret);\ - break; \ - case 8: \ - __put_user_asm(x, ptr, retval, "q", "", "Zr", errret); \ - break; \ - default: \ - __put_user_bad(); \ - } \ -} while (0) - -/* FIXME: this hack is definitely wrong -AK */ -struct __large_struct { unsigned long buf[100]; }; -#define __m(x) (*(struct __large_struct __user *)(x)) - -/* - * Tell gcc we read from memory instead of writing: this is because - * we do not write to any memory gcc knows about, so there are no - * aliasing issues. - */ -#define __put_user_asm(x, addr, err, itype, rtype, ltype, errno) \ - asm volatile("1: mov"itype" %"rtype"1,%2\n" \ - "2:\n" \ - ".section .fixup, \"ax\"\n" \ - "3: mov %3,%0\n" \ - " jmp 2b\n" \ - ".previous\n" \ - _ASM_EXTABLE(1b, 3b) \ - : "=r"(err) \ - : ltype (x), "m" (__m(addr)), "i" (errno), "0" (err)) - - #define __get_user_nocheck(x, ptr, size) \ ({ \ int __gu_err; \ -- cgit v1.2.2 From 6fd4725d75c5049641640ce23fa5896501dfbd42 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Wed, 25 Jun 2008 11:57:33 -0300 Subject: x86: don't always use EFAULT on __get_user_size. Let the user of the macro specify the desired return. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess_64.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/asm-x86/uaccess_64.h b/include/asm-x86/uaccess_64.h index 42c01aa70e72..e0875d7ae898 100644 --- a/include/asm-x86/uaccess_64.h +++ b/include/asm-x86/uaccess_64.h @@ -61,27 +61,27 @@ extern void __put_user_bad(void); ({ \ int __gu_err; \ unsigned long __gu_val; \ - __get_user_size(__gu_val, (ptr), (size), __gu_err); \ + __get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT);\ (x) = (__force typeof(*(ptr)))__gu_val; \ __gu_err; \ }) -#define __get_user_size(x, ptr, size, retval) \ +#define __get_user_size(x, ptr, size, retval, errret) \ do { \ retval = 0; \ __chk_user_ptr(ptr); \ switch (size) { \ case 1: \ - __get_user_asm(x, ptr, retval, "b", "b", "=q", -EFAULT);\ + __get_user_asm(x, ptr, retval, "b", "b", "=q", errret);\ break; \ case 2: \ - __get_user_asm(x, ptr, retval, "w", "w", "=r", -EFAULT);\ + __get_user_asm(x, ptr, retval, "w", "w", "=r", errret);\ break; \ case 4: \ - __get_user_asm(x, ptr, retval, "l", "k", "=r", -EFAULT);\ + __get_user_asm(x, ptr, retval, "l", "k", "=r", errret);\ break; \ case 8: \ - __get_user_asm(x, ptr, retval, "q", "", "=r", -EFAULT); \ + __get_user_asm(x, ptr, retval, "q", "", "=r", errret); \ break; \ default: \ (x) = __get_user_bad(); \ -- cgit v1.2.2 From 3f168221167ca7a844fde3bf58e1c7ca0bf9741e Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Wed, 25 Jun 2008 12:48:47 -0300 Subject: x86: merge __get_user_asm and its users. Move __get_user_asm and __get_user_size and __get_user_nocheck to uaccess.h. This requires us to define a macro at __get_user_size for the 64-bit access case. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess.h | 50 +++++++++++++++++++++++++++++++++++++++++++- include/asm-x86/uaccess_32.h | 41 ------------------------------------ include/asm-x86/uaccess_64.h | 43 ------------------------------------- 3 files changed, 49 insertions(+), 85 deletions(-) (limited to 'include') diff --git a/include/asm-x86/uaccess.h b/include/asm-x86/uaccess.h index bcda5d075921..4353b2267a02 100644 --- a/include/asm-x86/uaccess.h +++ b/include/asm-x86/uaccess.h @@ -233,6 +233,47 @@ do { \ #endif +#ifdef CONFIG_X86_32 +#define __get_user_asm_u64(x, ptr, retval, errret) (x) = __get_user_bad() +#else +#define __get_user_asm_u64(x, ptr, retval, errret) \ + __get_user_asm(x, ptr, retval, "q", "", "=r", errret) +#endif + +#define __get_user_size(x, ptr, size, retval, errret) \ +do { \ + retval = 0; \ + __chk_user_ptr(ptr); \ + switch (size) { \ + case 1: \ + __get_user_asm(x, ptr, retval, "b", "b", "=q", errret); \ + break; \ + case 2: \ + __get_user_asm(x, ptr, retval, "w", "w", "=r", errret); \ + break; \ + case 4: \ + __get_user_asm(x, ptr, retval, "l", "k", "=r", errret); \ + break; \ + case 8: \ + __get_user_asm_u64(x, ptr, retval, errret); \ + break; \ + default: \ + (x) = __get_user_bad(); \ + } \ +} while (0) + +#define __get_user_asm(x, addr, err, itype, rtype, ltype, errret) \ + asm volatile("1: mov"itype" %2,%"rtype"1\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: mov %3,%0\n" \ + " xor"itype" %"rtype"1,%"rtype"1\n" \ + " jmp 2b\n" \ + ".previous\n" \ + _ASM_EXTABLE(1b, 3b) \ + : "=r" (err), ltype(x) \ + : "m" (__m(addr)), "i" (errret), "0" (err)) + #define __put_user_nocheck(x, ptr, size) \ ({ \ long __pu_err; \ @@ -240,7 +281,14 @@ do { \ __pu_err; \ }) - +#define __get_user_nocheck(x, ptr, size) \ +({ \ + long __gu_err; \ + unsigned long __gu_val; \ + __get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \ + (x) = (__force __typeof__(*(ptr)))__gu_val; \ + __gu_err; \ +}) /* FIXME: this hack is definitely wrong -AK */ struct __large_struct { unsigned long buf[100]; }; diff --git a/include/asm-x86/uaccess_32.h b/include/asm-x86/uaccess_32.h index fab755781b9b..ebfe6b23ba57 100644 --- a/include/asm-x86/uaccess_32.h +++ b/include/asm-x86/uaccess_32.h @@ -145,47 +145,6 @@ extern void __put_user_8(void); #define __put_user(x, ptr) \ __put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr))) -#define __get_user_nocheck(x, ptr, size) \ -({ \ - long __gu_err; \ - unsigned long __gu_val; \ - __get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT); \ - (x) = (__typeof__(*(ptr)))__gu_val; \ - __gu_err; \ -}) - -#define __get_user_size(x, ptr, size, retval, errret) \ -do { \ - retval = 0; \ - __chk_user_ptr(ptr); \ - switch (size) { \ - case 1: \ - __get_user_asm(x, ptr, retval, "b", "b", "=q", errret); \ - break; \ - case 2: \ - __get_user_asm(x, ptr, retval, "w", "w", "=r", errret); \ - break; \ - case 4: \ - __get_user_asm(x, ptr, retval, "l", "", "=r", errret); \ - break; \ - default: \ - (x) = __get_user_bad(); \ - } \ -} while (0) - -#define __get_user_asm(x, addr, err, itype, rtype, ltype, errret) \ - asm volatile("1: mov"itype" %2,%"rtype"1\n" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: movl %3,%0\n" \ - " xor"itype" %"rtype"1,%"rtype"1\n" \ - " jmp 2b\n" \ - ".previous\n" \ - _ASM_EXTABLE(1b, 3b) \ - : "=r" (err), ltype (x) \ - : "m" (__m(addr)), "i" (errret), "0" (err)) - - unsigned long __must_check __copy_to_user_ll (void __user *to, const void *from, unsigned long n); unsigned long __must_check __copy_from_user_ll diff --git a/include/asm-x86/uaccess_64.h b/include/asm-x86/uaccess_64.h index e0875d7ae898..42a9769687e9 100644 --- a/include/asm-x86/uaccess_64.h +++ b/include/asm-x86/uaccess_64.h @@ -57,49 +57,6 @@ extern void __put_user_bad(void); __pu_err; \ }) -#define __get_user_nocheck(x, ptr, size) \ -({ \ - int __gu_err; \ - unsigned long __gu_val; \ - __get_user_size(__gu_val, (ptr), (size), __gu_err, -EFAULT);\ - (x) = (__force typeof(*(ptr)))__gu_val; \ - __gu_err; \ -}) - -#define __get_user_size(x, ptr, size, retval, errret) \ -do { \ - retval = 0; \ - __chk_user_ptr(ptr); \ - switch (size) { \ - case 1: \ - __get_user_asm(x, ptr, retval, "b", "b", "=q", errret);\ - break; \ - case 2: \ - __get_user_asm(x, ptr, retval, "w", "w", "=r", errret);\ - break; \ - case 4: \ - __get_user_asm(x, ptr, retval, "l", "k", "=r", errret);\ - break; \ - case 8: \ - __get_user_asm(x, ptr, retval, "q", "", "=r", errret); \ - break; \ - default: \ - (x) = __get_user_bad(); \ - } \ -} while (0) - -#define __get_user_asm(x, addr, err, itype, rtype, ltype, errno) \ - asm volatile("1: mov"itype" %2,%"rtype"1\n" \ - "2:\n" \ - ".section .fixup, \"ax\"\n" \ - "3: mov %3,%0\n" \ - " xor"itype" %"rtype"1,%"rtype"1\n" \ - " jmp 2b\n" \ - ".previous\n" \ - _ASM_EXTABLE(1b, 3b) \ - : "=r" (err), ltype (x) \ - : "m" (__m(addr)), "i"(errno), "0"(err)) - /* * Copy To/From Userspace */ -- cgit v1.2.2 From 64a978c1e3b2c0e2b663caf54719319919c5c17f Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Wed, 25 Jun 2008 12:59:37 -0300 Subject: x86: be more explicit in __put_user_x. For both __put_user_x and __put_user_8 macros, pass the error variable explicitly. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess_32.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/asm-x86/uaccess_32.h b/include/asm-x86/uaccess_32.h index ebfe6b23ba57..2c9067324d2c 100644 --- a/include/asm-x86/uaccess_32.h +++ b/include/asm-x86/uaccess_32.h @@ -31,11 +31,11 @@ extern void __put_user_2(void); extern void __put_user_4(void); extern void __put_user_8(void); -#define __put_user_x(size, x, ptr) \ +#define __put_user_x(size, x, ptr, __ret_pu) \ asm volatile("call __put_user_" #size : "=a" (__ret_pu) \ :"0" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx") -#define __put_user_8(x, ptr) \ +#define __put_user_8(x, ptr, __ret_pu) \ asm volatile("call __put_user_8" : "=a" (__ret_pu) \ : "A" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx") @@ -66,19 +66,19 @@ extern void __put_user_8(void); __pu_val = x; \ switch (sizeof(*(ptr))) { \ case 1: \ - __put_user_x(1, __pu_val, ptr); \ + __put_user_x(1, __pu_val, ptr, __ret_pu); \ break; \ case 2: \ - __put_user_x(2, __pu_val, ptr); \ + __put_user_x(2, __pu_val, ptr, __ret_pu); \ break; \ case 4: \ - __put_user_x(4, __pu_val, ptr); \ + __put_user_x(4, __pu_val, ptr, __ret_pu); \ break; \ case 8: \ - __put_user_8(__pu_val, ptr); \ + __put_user_8(__pu_val, ptr, __ret_pu); \ break; \ default: \ - __put_user_x(X, __pu_val, ptr); \ + __put_user_x(X, __pu_val, ptr, __ret_pu); \ break; \ } \ __ret_pu; \ -- cgit v1.2.2 From ec840956d269e2beefe3a1c0fd7c1c70a199087f Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Wed, 25 Jun 2008 13:00:48 -0300 Subject: x86: turn __put_user_check directly into put_user. We also check user pointer in x86_64 put_user, the way i386 does. In a separate patch for bisecting purposes. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess_64.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/asm-x86/uaccess_64.h b/include/asm-x86/uaccess_64.h index 42a9769687e9..9139854d37b0 100644 --- a/include/asm-x86/uaccess_64.h +++ b/include/asm-x86/uaccess_64.h @@ -23,9 +23,6 @@ extern void __put_user_bad(void); :"c" (ptr),"a" (x) \ :"ebx") -#define put_user(x, ptr) \ - __put_user_check((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr))) - #define __get_user(x, ptr) \ __get_user_nocheck((x), (ptr), sizeof(*(ptr))) #define __put_user(x, ptr) \ @@ -34,11 +31,12 @@ extern void __put_user_bad(void); #define __get_user_unaligned __get_user #define __put_user_unaligned __put_user -#define __put_user_check(x, ptr, size) \ +#define put_user(x, ptr) \ ({ \ int __pu_err; \ typeof(*(ptr)) __user *__pu_addr = (ptr); \ - switch (size) { \ + __chk_user_ptr(ptr); \ + switch (sizeof(*(ptr))) { \ case 1: \ __put_user_x(1, __pu_err, x, __pu_addr); \ break; \ -- cgit v1.2.2 From e30a44fdbf11c7ca3a0096d71790f176a4a09e03 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Wed, 25 Jun 2008 13:17:43 -0300 Subject: x86: merge put_user. Move both versions, which are highly similar, to uaccess.h. Note that, for x86_64, X86_WP_WORKS_OK is always defined. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess.h | 74 +++++++++++++++++++++++++++++++++++++++++ include/asm-x86/uaccess_32.h | 79 -------------------------------------------- include/asm-x86/uaccess_64.h | 36 -------------------- 3 files changed, 74 insertions(+), 115 deletions(-) (limited to 'include') diff --git a/include/asm-x86/uaccess.h b/include/asm-x86/uaccess.h index 4353b2267a02..3a9092af5af0 100644 --- a/include/asm-x86/uaccess.h +++ b/include/asm-x86/uaccess.h @@ -178,6 +178,12 @@ extern int __get_user_bad(void); __ret_gu; \ }) +#define __put_user_x(size, x, ptr, __ret_pu) \ + asm volatile("call __put_user_" #size : "=a" (__ret_pu) \ + :"0" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx") + + + #ifdef CONFIG_X86_32 #define __put_user_u64(x, addr, err) \ asm volatile("1: movl %%eax,0(%2)\n" \ @@ -191,13 +197,71 @@ extern int __get_user_bad(void); _ASM_EXTABLE(2b, 4b) \ : "=r" (err) \ : "A" (x), "r" (addr), "i" (-EFAULT), "0" (err)) + +#define __put_user_x8(x, ptr, __ret_pu) \ + asm volatile("call __put_user_8" : "=a" (__ret_pu) \ + : "A" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx") #else #define __put_user_u64(x, ptr, retval) \ __put_user_asm(x, ptr, retval, "q", "", "Zr", -EFAULT) +#define __put_user_x8(x, ptr, __ret_pu) __put_user_x(8, x, ptr, __ret_pu) #endif +extern void __put_user_bad(void); + +/* + * Strange magic calling convention: pointer in %ecx, + * value in %eax(:%edx), return value in %eax. clobbers %rbx + */ +extern void __put_user_1(void); +extern void __put_user_2(void); +extern void __put_user_4(void); +extern void __put_user_8(void); + #ifdef CONFIG_X86_WP_WORKS_OK +/** + * put_user: - Write a simple value into user space. + * @x: Value to copy to user space. + * @ptr: Destination address, in user space. + * + * Context: User context only. This function may sleep. + * + * This macro copies a single simple value from kernel space to user + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and @x must be assignable + * to the result of dereferencing @ptr. + * + * Returns zero on success, or -EFAULT on error. + */ +#define put_user(x, ptr) \ +({ \ + int __ret_pu; \ + __typeof__(*(ptr)) __pu_val; \ + __chk_user_ptr(ptr); \ + __pu_val = x; \ + switch (sizeof(*(ptr))) { \ + case 1: \ + __put_user_x(1, __pu_val, ptr, __ret_pu); \ + break; \ + case 2: \ + __put_user_x(2, __pu_val, ptr, __ret_pu); \ + break; \ + case 4: \ + __put_user_x(4, __pu_val, ptr, __ret_pu); \ + break; \ + case 8: \ + __put_user_x8(__pu_val, ptr, __ret_pu); \ + break; \ + default: \ + __put_user_x(X, __pu_val, ptr, __ret_pu); \ + break; \ + } \ + __ret_pu; \ +}) + #define __put_user_size(x, ptr, size, retval, errret) \ do { \ retval = 0; \ @@ -231,6 +295,16 @@ do { \ retval = errret; \ } while (0) +#define put_user(x, ptr) \ +({ \ + int __ret_pu; \ + __typeof__(*(ptr))__pus_tmp = x; \ + __ret_pu = 0; \ + if (unlikely(__copy_to_user_ll(ptr, &__pus_tmp, \ + sizeof(*(ptr))) != 0)) \ + __ret_pu = -EFAULT; \ + __ret_pu; \ +}) #endif #ifdef CONFIG_X86_32 diff --git a/include/asm-x86/uaccess_32.h b/include/asm-x86/uaccess_32.h index 2c9067324d2c..e5c0437f509b 100644 --- a/include/asm-x86/uaccess_32.h +++ b/include/asm-x86/uaccess_32.h @@ -20,85 +20,6 @@ extern struct movsl_mask { } ____cacheline_aligned_in_smp movsl_mask; #endif -extern void __put_user_bad(void); - -/* - * Strange magic calling convention: pointer in %ecx, - * value in %eax(:%edx), return value in %eax, no clobbers. - */ -extern void __put_user_1(void); -extern void __put_user_2(void); -extern void __put_user_4(void); -extern void __put_user_8(void); - -#define __put_user_x(size, x, ptr, __ret_pu) \ - asm volatile("call __put_user_" #size : "=a" (__ret_pu) \ - :"0" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx") - -#define __put_user_8(x, ptr, __ret_pu) \ - asm volatile("call __put_user_8" : "=a" (__ret_pu) \ - : "A" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx") - - -/** - * put_user: - Write a simple value into user space. - * @x: Value to copy to user space. - * @ptr: Destination address, in user space. - * - * Context: User context only. This function may sleep. - * - * This macro copies a single simple value from kernel space to user - * space. It supports simple types like char and int, but not larger - * data types like structures or arrays. - * - * @ptr must have pointer-to-simple-variable type, and @x must be assignable - * to the result of dereferencing @ptr. - * - * Returns zero on success, or -EFAULT on error. - */ -#ifdef CONFIG_X86_WP_WORKS_OK - -#define put_user(x, ptr) \ -({ \ - int __ret_pu; \ - __typeof__(*(ptr)) __pu_val; \ - __chk_user_ptr(ptr); \ - __pu_val = x; \ - switch (sizeof(*(ptr))) { \ - case 1: \ - __put_user_x(1, __pu_val, ptr, __ret_pu); \ - break; \ - case 2: \ - __put_user_x(2, __pu_val, ptr, __ret_pu); \ - break; \ - case 4: \ - __put_user_x(4, __pu_val, ptr, __ret_pu); \ - break; \ - case 8: \ - __put_user_8(__pu_val, ptr, __ret_pu); \ - break; \ - default: \ - __put_user_x(X, __pu_val, ptr, __ret_pu); \ - break; \ - } \ - __ret_pu; \ -}) - -#else -#define put_user(x, ptr) \ -({ \ - int __ret_pu; \ - __typeof__(*(ptr))__pus_tmp = x; \ - __ret_pu = 0; \ - if (unlikely(__copy_to_user_ll(ptr, &__pus_tmp, \ - sizeof(*(ptr))) != 0)) \ - __ret_pu = -EFAULT; \ - __ret_pu; \ -}) - - -#endif - /** * __get_user: - Get a simple variable from user space, with less checking. * @x: Variable to store result. diff --git a/include/asm-x86/uaccess_64.h b/include/asm-x86/uaccess_64.h index 9139854d37b0..2e75a5d1a17a 100644 --- a/include/asm-x86/uaccess_64.h +++ b/include/asm-x86/uaccess_64.h @@ -11,18 +11,6 @@ #define ARCH_HAS_SEARCH_EXTABLE -extern void __put_user_1(void); -extern void __put_user_2(void); -extern void __put_user_4(void); -extern void __put_user_8(void); -extern void __put_user_bad(void); - -#define __put_user_x(size, ret, x, ptr) \ - asm volatile("call __put_user_" #size \ - :"=a" (ret) \ - :"c" (ptr),"a" (x) \ - :"ebx") - #define __get_user(x, ptr) \ __get_user_nocheck((x), (ptr), sizeof(*(ptr))) #define __put_user(x, ptr) \ @@ -31,30 +19,6 @@ extern void __put_user_bad(void); #define __get_user_unaligned __get_user #define __put_user_unaligned __put_user -#define put_user(x, ptr) \ -({ \ - int __pu_err; \ - typeof(*(ptr)) __user *__pu_addr = (ptr); \ - __chk_user_ptr(ptr); \ - switch (sizeof(*(ptr))) { \ - case 1: \ - __put_user_x(1, __pu_err, x, __pu_addr); \ - break; \ - case 2: \ - __put_user_x(2, __pu_err, x, __pu_addr); \ - break; \ - case 4: \ - __put_user_x(4, __pu_err, x, __pu_addr); \ - break; \ - case 8: \ - __put_user_x(8, __pu_err, x, __pu_addr); \ - break; \ - default: \ - __put_user_bad(); \ - } \ - __pu_err; \ -}) - /* * Copy To/From Userspace */ -- cgit v1.2.2 From 8cb834e99f44bd56409b794504ae2b170675fc92 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Wed, 25 Jun 2008 14:43:30 -0300 Subject: x86: move __get_user and __put_user into uaccess.h. We also carry the unaligned version with us. Only x86_64 uses it, but there's no problem in defining it. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess.h | 47 ++++++++++++++++++++++++++++++++++++++++++++ include/asm-x86/uaccess_32.h | 46 ------------------------------------------- include/asm-x86/uaccess_64.h | 8 -------- 3 files changed, 47 insertions(+), 54 deletions(-) (limited to 'include') diff --git a/include/asm-x86/uaccess.h b/include/asm-x86/uaccess.h index 3a9092af5af0..7c7b46af6368 100644 --- a/include/asm-x86/uaccess.h +++ b/include/asm-x86/uaccess.h @@ -383,7 +383,54 @@ struct __large_struct { unsigned long buf[100]; }; _ASM_EXTABLE(1b, 3b) \ : "=r"(err) \ : ltype(x), "m" (__m(addr)), "i" (errret), "0" (err)) +/** + * __get_user: - Get a simple variable from user space, with less checking. + * @x: Variable to store result. + * @ptr: Source address, in user space. + * + * Context: User context only. This function may sleep. + * + * This macro copies a single simple variable from user space to kernel + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and the result of + * dereferencing @ptr must be assignable to @x without a cast. + * + * Caller must check the pointer with access_ok() before calling this + * function. + * + * Returns zero on success, or -EFAULT on error. + * On error, the variable @x is set to zero. + */ + +#define __get_user(x, ptr) \ + __get_user_nocheck((x), (ptr), sizeof(*(ptr))) +/** + * __put_user: - Write a simple value into user space, with less checking. + * @x: Value to copy to user space. + * @ptr: Destination address, in user space. + * + * Context: User context only. This function may sleep. + * + * This macro copies a single simple value from kernel space to user + * space. It supports simple types like char and int, but not larger + * data types like structures or arrays. + * + * @ptr must have pointer-to-simple-variable type, and @x must be assignable + * to the result of dereferencing @ptr. + * + * Caller must check the pointer with access_ok() before calling this + * function. + * + * Returns zero on success, or -EFAULT on error. + */ + +#define __put_user(x, ptr) \ + __put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr))) +#define __get_user_unaligned __get_user +#define __put_user_unaligned __put_user #ifdef CONFIG_X86_32 # include "uaccess_32.h" diff --git a/include/asm-x86/uaccess_32.h b/include/asm-x86/uaccess_32.h index e5c0437f509b..d3b5bf88ea86 100644 --- a/include/asm-x86/uaccess_32.h +++ b/include/asm-x86/uaccess_32.h @@ -20,52 +20,6 @@ extern struct movsl_mask { } ____cacheline_aligned_in_smp movsl_mask; #endif -/** - * __get_user: - Get a simple variable from user space, with less checking. - * @x: Variable to store result. - * @ptr: Source address, in user space. - * - * Context: User context only. This function may sleep. - * - * This macro copies a single simple variable from user space to kernel - * space. It supports simple types like char and int, but not larger - * data types like structures or arrays. - * - * @ptr must have pointer-to-simple-variable type, and the result of - * dereferencing @ptr must be assignable to @x without a cast. - * - * Caller must check the pointer with access_ok() before calling this - * function. - * - * Returns zero on success, or -EFAULT on error. - * On error, the variable @x is set to zero. - */ -#define __get_user(x, ptr) \ - __get_user_nocheck((x), (ptr), sizeof(*(ptr))) - - -/** - * __put_user: - Write a simple value into user space, with less checking. - * @x: Value to copy to user space. - * @ptr: Destination address, in user space. - * - * Context: User context only. This function may sleep. - * - * This macro copies a single simple value from kernel space to user - * space. It supports simple types like char and int, but not larger - * data types like structures or arrays. - * - * @ptr must have pointer-to-simple-variable type, and @x must be assignable - * to the result of dereferencing @ptr. - * - * Caller must check the pointer with access_ok() before calling this - * function. - * - * Returns zero on success, or -EFAULT on error. - */ -#define __put_user(x, ptr) \ - __put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr))) - unsigned long __must_check __copy_to_user_ll (void __user *to, const void *from, unsigned long n); unsigned long __must_check __copy_from_user_ll diff --git a/include/asm-x86/uaccess_64.h b/include/asm-x86/uaccess_64.h index 2e75a5d1a17a..b5bacd613686 100644 --- a/include/asm-x86/uaccess_64.h +++ b/include/asm-x86/uaccess_64.h @@ -11,14 +11,6 @@ #define ARCH_HAS_SEARCH_EXTABLE -#define __get_user(x, ptr) \ - __get_user_nocheck((x), (ptr), sizeof(*(ptr))) -#define __put_user(x, ptr) \ - __put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr))) - -#define __get_user_unaligned __get_user -#define __put_user_unaligned __put_user - /* * Copy To/From Userspace */ -- cgit v1.2.2 From 8bc7de0c5dc0a5d3bcdc04bac6de0c799f91c5e4 Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Wed, 25 Jun 2008 14:53:41 -0300 Subject: x86: put movsl_mask into uaccess.h. x86_64 does not need it, but it won't have X86_INTEL_USERCOPY defined either. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess.h | 9 +++++++++ include/asm-x86/uaccess_32.h | 9 --------- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/asm-x86/uaccess.h b/include/asm-x86/uaccess.h index 7c7b46af6368..0c4ab788d017 100644 --- a/include/asm-x86/uaccess.h +++ b/include/asm-x86/uaccess.h @@ -432,6 +432,15 @@ struct __large_struct { unsigned long buf[100]; }; #define __get_user_unaligned __get_user #define __put_user_unaligned __put_user +/* + * movsl can be slow when source and dest are not both 8-byte aligned + */ +#ifdef CONFIG_X86_INTEL_USERCOPY +extern struct movsl_mask { + int mask; +} ____cacheline_aligned_in_smp movsl_mask; +#endif + #ifdef CONFIG_X86_32 # include "uaccess_32.h" #else diff --git a/include/asm-x86/uaccess_32.h b/include/asm-x86/uaccess_32.h index d3b5bf88ea86..3467749c6beb 100644 --- a/include/asm-x86/uaccess_32.h +++ b/include/asm-x86/uaccess_32.h @@ -11,15 +11,6 @@ #include #include -/* - * movsl can be slow when source and dest are not both 8-byte aligned - */ -#ifdef CONFIG_X86_INTEL_USERCOPY -extern struct movsl_mask { - int mask; -} ____cacheline_aligned_in_smp movsl_mask; -#endif - unsigned long __must_check __copy_to_user_ll (void __user *to, const void *from, unsigned long n); unsigned long __must_check __copy_from_user_ll -- cgit v1.2.2 From 22cac1670786108ccd4caa0656c39fa4ba69fa7d Mon Sep 17 00:00:00 2001 From: Glauber Costa Date: Wed, 25 Jun 2008 14:56:53 -0300 Subject: x86: define architectural characteristics in uaccess.h. Remove them from the arch-specific file. Signed-off-by: Glauber Costa Signed-off-by: H. Peter Anvin Signed-off-by: Ingo Molnar --- include/asm-x86/uaccess.h | 3 +++ include/asm-x86/uaccess_32.h | 2 -- include/asm-x86/uaccess_64.h | 3 --- 3 files changed, 3 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/asm-x86/uaccess.h b/include/asm-x86/uaccess.h index 0c4ab788d017..f6fa4d841bbc 100644 --- a/include/asm-x86/uaccess.h +++ b/include/asm-x86/uaccess.h @@ -441,9 +441,12 @@ extern struct movsl_mask { } ____cacheline_aligned_in_smp movsl_mask; #endif +#define ARCH_HAS_NOCACHE_UACCESS 1 + #ifdef CONFIG_X86_32 # include "uaccess_32.h" #else +# define ARCH_HAS_SEARCH_EXTABLE # include "uaccess_64.h" #endif diff --git a/include/asm-x86/uaccess_32.h b/include/asm-x86/uaccess_32.h index 3467749c6beb..6fdef39a0bcb 100644 --- a/include/asm-x86/uaccess_32.h +++ b/include/asm-x86/uaccess_32.h @@ -156,8 +156,6 @@ __copy_from_user(void *to, const void __user *from, unsigned long n) return __copy_from_user_ll(to, from, n); } -#define ARCH_HAS_NOCACHE_UACCESS - static __always_inline unsigned long __copy_from_user_nocache(void *to, const void __user *from, unsigned long n) { diff --git a/include/asm-x86/uaccess_64.h b/include/asm-x86/uaccess_64.h index b5bacd613686..4e3ec004e14a 100644 --- a/include/asm-x86/uaccess_64.h +++ b/include/asm-x86/uaccess_64.h @@ -9,8 +9,6 @@ #include #include -#define ARCH_HAS_SEARCH_EXTABLE - /* * Copy To/From Userspace */ @@ -180,7 +178,6 @@ __copy_to_user_inatomic(void __user *dst, const void *src, unsigned size) return copy_user_generic((__force void *)dst, src, size); } -#define ARCH_HAS_NOCACHE_UACCESS 1 extern long __copy_user_nocache(void *dst, const void __user *src, unsigned size, int zerorest); -- cgit v1.2.2