Skip to content

Commit f6bff78

Browse files
xhackerustcpalmer-dabbelt
authored andcommitted
riscv: uaccess: use 'asm_goto_output' for get_user()
With 'asm goto' we don't need to test the error etc, the exception just jumps to the error handling directly. Unlike put_user(), get_user() must work around GCC bugs [1] when using output clobbers in an asm goto statement. Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113921 # 1 Signed-off-by: Jisheng Zhang <[email protected]> [Cyril Bur: Rewritten commit message] Signed-off-by: Cyril Bur <[email protected]> Reviewed-by: Alexandre Ghiti <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent cdf647e commit f6bff78

File tree

1 file changed

+68
-27
lines changed

1 file changed

+68
-27
lines changed

arch/riscv/include/asm/uaccess.h

Lines changed: 68 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -96,27 +96,58 @@ static inline unsigned long __untagged_addr_remote(struct mm_struct *mm, unsigne
9696
* call.
9797
*/
9898

99-
#define __get_user_asm(insn, x, ptr, err) \
99+
#ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
100+
#define __get_user_asm(insn, x, ptr, label) \
101+
asm_goto_output( \
102+
"1:\n" \
103+
" " insn " %0, %1\n" \
104+
_ASM_EXTABLE_UACCESS_ERR(1b, %l2, %0) \
105+
: "=&r" (x) \
106+
: "m" (*(ptr)) : : label)
107+
#else /* !CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
108+
#define __get_user_asm(insn, x, ptr, label) \
100109
do { \
101-
__typeof__(x) __x; \
110+
long __gua_err = 0; \
102111
__asm__ __volatile__ ( \
103112
"1:\n" \
104113
" " insn " %1, %2\n" \
105114
"2:\n" \
106115
_ASM_EXTABLE_UACCESS_ERR_ZERO(1b, 2b, %0, %1) \
107-
: "+r" (err), "=&r" (__x) \
116+
: "+r" (__gua_err), "=&r" (x) \
108117
: "m" (*(ptr))); \
109-
(x) = __x; \
118+
if (__gua_err) \
119+
goto label; \
110120
} while (0)
121+
#endif /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
111122

112123
#ifdef CONFIG_64BIT
113-
#define __get_user_8(x, ptr, err) \
114-
__get_user_asm("ld", x, ptr, err)
124+
#define __get_user_8(x, ptr, label) \
125+
__get_user_asm("ld", x, ptr, label)
115126
#else /* !CONFIG_64BIT */
116-
#define __get_user_8(x, ptr, err) \
127+
128+
#ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
129+
#define __get_user_8(x, ptr, label) \
130+
u32 __user *__ptr = (u32 __user *)(ptr); \
131+
u32 __lo, __hi; \
132+
asm_goto_output( \
133+
"1:\n" \
134+
" lw %0, %2\n" \
135+
"2:\n" \
136+
" lw %1, %3\n" \
137+
_ASM_EXTABLE_UACCESS_ERR(1b, %l4, %0) \
138+
_ASM_EXTABLE_UACCESS_ERR(2b, %l4, %0) \
139+
: "=&r" (__lo), "=r" (__hi) \
140+
: "m" (__ptr[__LSW]), "m" (__ptr[__MSW]) \
141+
: : label); \
142+
(x) = (__typeof__(x))((__typeof__((x) - (x)))( \
143+
(((u64)__hi << 32) | __lo))); \
144+
145+
#else /* !CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
146+
#define __get_user_8(x, ptr, label) \
117147
do { \
118148
u32 __user *__ptr = (u32 __user *)(ptr); \
119149
u32 __lo, __hi; \
150+
long __gu8_err = 0; \
120151
__asm__ __volatile__ ( \
121152
"1:\n" \
122153
" lw %1, %3\n" \
@@ -125,35 +156,51 @@ do { \
125156
"3:\n" \
126157
_ASM_EXTABLE_UACCESS_ERR_ZERO(1b, 3b, %0, %1) \
127158
_ASM_EXTABLE_UACCESS_ERR_ZERO(2b, 3b, %0, %1) \
128-
: "+r" (err), "=&r" (__lo), "=r" (__hi) \
159+
: "+r" (__gu8_err), "=&r" (__lo), "=r" (__hi) \
129160
: "m" (__ptr[__LSW]), "m" (__ptr[__MSW])); \
130-
if (err) \
161+
if (__gu8_err) { \
131162
__hi = 0; \
132-
(x) = (__typeof__(x))((__typeof__((x)-(x)))( \
163+
goto label; \
164+
} \
165+
(x) = (__typeof__(x))((__typeof__((x) - (x)))( \
133166
(((u64)__hi << 32) | __lo))); \
134167
} while (0)
168+
#endif /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
169+
135170
#endif /* CONFIG_64BIT */
136171

137-
#define __get_user_nocheck(x, __gu_ptr, __gu_err) \
172+
#define __get_user_nocheck(x, __gu_ptr, label) \
138173
do { \
139174
switch (sizeof(*__gu_ptr)) { \
140175
case 1: \
141-
__get_user_asm("lb", (x), __gu_ptr, __gu_err); \
176+
__get_user_asm("lb", (x), __gu_ptr, label); \
142177
break; \
143178
case 2: \
144-
__get_user_asm("lh", (x), __gu_ptr, __gu_err); \
179+
__get_user_asm("lh", (x), __gu_ptr, label); \
145180
break; \
146181
case 4: \
147-
__get_user_asm("lw", (x), __gu_ptr, __gu_err); \
182+
__get_user_asm("lw", (x), __gu_ptr, label); \
148183
break; \
149184
case 8: \
150-
__get_user_8((x), __gu_ptr, __gu_err); \
185+
__get_user_8((x), __gu_ptr, label); \
151186
break; \
152187
default: \
153188
BUILD_BUG(); \
154189
} \
155190
} while (0)
156191

192+
#define __get_user_error(x, ptr, err) \
193+
do { \
194+
__label__ __gu_failed; \
195+
\
196+
__get_user_nocheck(x, ptr, __gu_failed); \
197+
err = 0; \
198+
break; \
199+
__gu_failed: \
200+
x = 0; \
201+
err = -EFAULT; \
202+
} while (0)
203+
157204
/**
158205
* __get_user: - Get a simple variable from user space, with less checking.
159206
* @x: Variable to store result.
@@ -178,13 +225,16 @@ do { \
178225
({ \
179226
const __typeof__(*(ptr)) __user *__gu_ptr = untagged_addr(ptr); \
180227
long __gu_err = 0; \
228+
__typeof__(x) __gu_val; \
181229
\
182230
__chk_user_ptr(__gu_ptr); \
183231
\
184232
__enable_user_access(); \
185-
__get_user_nocheck(x, __gu_ptr, __gu_err); \
233+
__get_user_error(__gu_val, __gu_ptr, __gu_err); \
186234
__disable_user_access(); \
187235
\
236+
(x) = __gu_val; \
237+
\
188238
__gu_err; \
189239
})
190240

@@ -369,13 +419,7 @@ unsigned long __must_check clear_user(void __user *to, unsigned long n)
369419
}
370420

371421
#define __get_kernel_nofault(dst, src, type, err_label) \
372-
do { \
373-
long __kr_err = 0; \
374-
\
375-
__get_user_nocheck(*((type *)(dst)), (type *)(src), __kr_err); \
376-
if (unlikely(__kr_err)) \
377-
goto err_label; \
378-
} while (0)
422+
__get_user_nocheck(*((type *)(dst)), (type *)(src), err_label)
379423

380424
#define __put_kernel_nofault(dst, src, type, err_label) \
381425
__put_user_nocheck(*((type *)(src)), (type *)(dst), err_label)
@@ -401,12 +445,9 @@ static inline void user_access_restore(unsigned long enabled) { }
401445
__put_user_nocheck(x, (ptr), label)
402446

403447
#define unsafe_get_user(x, ptr, label) do { \
404-
long __err = 0; \
405448
__inttype(*(ptr)) __gu_val; \
406-
__get_user_nocheck(__gu_val, (ptr), __err); \
449+
__get_user_nocheck(__gu_val, (ptr), label); \
407450
(x) = (__force __typeof__(*(ptr)))__gu_val; \
408-
if (__err) \
409-
goto label; \
410451
} while (0)
411452

412453
#define unsafe_copy_loop(dst, src, len, type, op, label) \

0 commit comments

Comments
 (0)