aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/uaccess.h19
-rw-r--r--arch/x86/kernel/i386_ksyms_32.c1
-rw-r--r--arch/x86/lib/getuser.S37
3 files changed, 48 insertions, 9 deletions
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index 1709801d18ec..1e963267d44e 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -151,8 +151,15 @@ extern int __get_user_bad(void);
151 * On error, the variable @x is set to zero. 151 * On error, the variable @x is set to zero.
152 */ 152 */
153#ifdef CONFIG_X86_32 153#ifdef CONFIG_X86_32
154#define __get_user_8(__ret_gu, __val_gu, ptr) \ 154#define __get_user_8(ret, x, ptr) \
155 __get_user_x(X, __ret_gu, __val_gu, ptr) 155do { \
156 register unsigned long long __xx asm("%edx"); \
157 asm volatile("call __get_user_8" \
158 : "=a" (ret), "=r" (__xx) \
159 : "0" (ptr)); \
160 (x) = __xx; \
161} while (0)
162
156#else 163#else
157#define __get_user_8(__ret_gu, __val_gu, ptr) \ 164#define __get_user_8(__ret_gu, __val_gu, ptr) \
158 __get_user_x(8, __ret_gu, __val_gu, ptr) 165 __get_user_x(8, __ret_gu, __val_gu, ptr)
@@ -162,6 +169,7 @@ extern int __get_user_bad(void);
162({ \ 169({ \
163 int __ret_gu; \ 170 int __ret_gu; \
164 unsigned long __val_gu; \ 171 unsigned long __val_gu; \
172 unsigned long long __val_gu8; \
165 __chk_user_ptr(ptr); \ 173 __chk_user_ptr(ptr); \
166 might_fault(); \ 174 might_fault(); \
167 switch (sizeof(*(ptr))) { \ 175 switch (sizeof(*(ptr))) { \
@@ -175,13 +183,16 @@ extern int __get_user_bad(void);
175 __get_user_x(4, __ret_gu, __val_gu, ptr); \ 183 __get_user_x(4, __ret_gu, __val_gu, ptr); \
176 break; \ 184 break; \
177 case 8: \ 185 case 8: \
178 __get_user_8(__ret_gu, __val_gu, ptr); \ 186 __get_user_8(__ret_gu, __val_gu8, ptr); \
179 break; \ 187 break; \
180 default: \ 188 default: \
181 __get_user_x(X, __ret_gu, __val_gu, ptr); \ 189 __get_user_x(X, __ret_gu, __val_gu, ptr); \
182 break; \ 190 break; \
183 } \ 191 } \
184 (x) = (__typeof__(*(ptr)))__val_gu; \ 192 if (sizeof(*(ptr)) == 8) \
193 (x) = (__typeof__(*(ptr)))__val_gu8; \
194 else \
195 (x) = (__typeof__(*(ptr)))__val_gu; \
185 __ret_gu; \ 196 __ret_gu; \
186}) 197})
187 198
diff --git a/arch/x86/kernel/i386_ksyms_32.c b/arch/x86/kernel/i386_ksyms_32.c
index 9c3bd4a2050e..0fa69127209a 100644
--- a/arch/x86/kernel/i386_ksyms_32.c
+++ b/arch/x86/kernel/i386_ksyms_32.c
@@ -26,6 +26,7 @@ EXPORT_SYMBOL(csum_partial_copy_generic);
26EXPORT_SYMBOL(__get_user_1); 26EXPORT_SYMBOL(__get_user_1);
27EXPORT_SYMBOL(__get_user_2); 27EXPORT_SYMBOL(__get_user_2);
28EXPORT_SYMBOL(__get_user_4); 28EXPORT_SYMBOL(__get_user_4);
29EXPORT_SYMBOL(__get_user_8);
29 30
30EXPORT_SYMBOL(__put_user_1); 31EXPORT_SYMBOL(__put_user_1);
31EXPORT_SYMBOL(__put_user_2); 32EXPORT_SYMBOL(__put_user_2);
diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S
index 156b9c804670..d3bf9f99ca77 100644
--- a/arch/x86/lib/getuser.S
+++ b/arch/x86/lib/getuser.S
@@ -15,11 +15,10 @@
15 * __get_user_X 15 * __get_user_X
16 * 16 *
17 * Inputs: %[r|e]ax contains the address. 17 * Inputs: %[r|e]ax contains the address.
18 * The register is modified, but all changes are undone
19 * before returning because the C code doesn't know about it.
20 * 18 *
21 * Outputs: %[r|e]ax is error code (0 or -EFAULT) 19 * Outputs: %[r|e]ax is error code (0 or -EFAULT)
22 * %[r|e]dx contains zero-extended value 20 * %[r|e]dx contains zero-extended value
21 * %ecx contains the high half for 32-bit __get_user_8
23 * 22 *
24 * 23 *
25 * These functions should not modify any other registers, 24 * These functions should not modify any other registers,
@@ -79,22 +78,35 @@ ENTRY(__get_user_4)
79 CFI_ENDPROC 78 CFI_ENDPROC
80ENDPROC(__get_user_4) 79ENDPROC(__get_user_4)
81 80
82#ifdef CONFIG_X86_64
83ENTRY(__get_user_8) 81ENTRY(__get_user_8)
84 CFI_STARTPROC 82 CFI_STARTPROC
83#ifdef CONFIG_X86_64
85 add $7,%_ASM_AX 84 add $7,%_ASM_AX
86 jc bad_get_user 85 jc bad_get_user
87 GET_THREAD_INFO(%_ASM_DX) 86 GET_THREAD_INFO(%_ASM_DX)
88 cmp TI_addr_limit(%_ASM_DX),%_ASM_AX 87 cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
89 jae bad_get_user 88 jae bad_get_user
90 ASM_STAC 89 ASM_STAC
914: movq -7(%_ASM_AX),%_ASM_DX 904: movq -7(%_ASM_AX),%_ASM_DX
92 xor %eax,%eax 91 xor %eax,%eax
93 ASM_CLAC 92 ASM_CLAC
94 ret 93 ret
94#else
95 add $7,%_ASM_AX
96 jc bad_get_user_8
97 GET_THREAD_INFO(%_ASM_DX)
98 cmp TI_addr_limit(%_ASM_DX),%_ASM_AX
99 jae bad_get_user_8
100 ASM_STAC
1014: mov -7(%_ASM_AX),%edx
1025: mov -3(%_ASM_AX),%ecx
103 xor %eax,%eax
104 ASM_CLAC
105 ret
106#endif
95 CFI_ENDPROC 107 CFI_ENDPROC
96ENDPROC(__get_user_8) 108ENDPROC(__get_user_8)
97#endif 109
98 110
99bad_get_user: 111bad_get_user:
100 CFI_STARTPROC 112 CFI_STARTPROC
@@ -105,9 +117,24 @@ bad_get_user:
105 CFI_ENDPROC 117 CFI_ENDPROC
106END(bad_get_user) 118END(bad_get_user)
107 119
120#ifdef CONFIG_X86_32
121bad_get_user_8:
122 CFI_STARTPROC
123 xor %edx,%edx
124 xor %ecx,%ecx
125 mov $(-EFAULT),%_ASM_AX
126 ASM_CLAC
127 ret
128 CFI_ENDPROC
129END(bad_get_user_8)
130#endif
131
108 _ASM_EXTABLE(1b,bad_get_user) 132 _ASM_EXTABLE(1b,bad_get_user)
109 _ASM_EXTABLE(2b,bad_get_user) 133 _ASM_EXTABLE(2b,bad_get_user)
110 _ASM_EXTABLE(3b,bad_get_user) 134 _ASM_EXTABLE(3b,bad_get_user)
111#ifdef CONFIG_X86_64 135#ifdef CONFIG_X86_64
112 _ASM_EXTABLE(4b,bad_get_user) 136 _ASM_EXTABLE(4b,bad_get_user)
137#else
138 _ASM_EXTABLE(4b,bad_get_user_8)
139 _ASM_EXTABLE(5b,bad_get_user_8)
113#endif 140#endif