parisc: Fix some apparent put_user() failures

After commit 4b9d2a731c ("parisc: Switch user access functions
to signal errors in r29 instead of r8") bash suddenly started
to report those warnings after login:

-bash: cannot set terminal process group (-1): Bad file descriptor
-bash: no job control in this shell

It turned out, that a function call inside a put_user(), e.g.:
put_user(vt_do_kdgkbmode(console), (int __user *)arg);
clobbered the error register (r29) and thus the put_user() call itself
seem to have failed.

Rearrange the C-code to pre-calculate the intermediate value
and then do the put_user().
Additionally prefer the "+" constraint on pu_err and gu_err registers
to tell the compiler that those operands are both read and written by
the assembly instruction.

Reported-by: John David Anglin <dave.anglin@bell.net>
Signed-off-by: Helge Deller <deller@gmx.de>
Fixes: 4b9d2a731c ("parisc: Switch user access functions to signal errors in r29 instead of r8")
Signed-off-by: Helge Deller <deller@gmx.de>
This commit is contained in:
Helge Deller 2022-02-13 22:52:11 +01:00
parent b160628e9e
commit dbd0b42350

View File

@ -89,8 +89,8 @@ struct exception_table_entry {
__asm__("1: " ldx " 0(" sr "%2),%0\n" \ __asm__("1: " ldx " 0(" sr "%2),%0\n" \
"9:\n" \ "9:\n" \
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \
: "=r"(__gu_val), "=r"(__gu_err) \ : "=r"(__gu_val), "+r"(__gu_err) \
: "r"(ptr), "1"(__gu_err)); \ : "r"(ptr)); \
\ \
(val) = (__force __typeof__(*(ptr))) __gu_val; \ (val) = (__force __typeof__(*(ptr))) __gu_val; \
} }
@ -123,8 +123,8 @@ struct exception_table_entry {
"9:\n" \ "9:\n" \
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \
: "=&r"(__gu_tmp.l), "=r"(__gu_err) \ : "=&r"(__gu_tmp.l), "+r"(__gu_err) \
: "r"(ptr), "1"(__gu_err)); \ : "r"(ptr)); \
\ \
(val) = __gu_tmp.t; \ (val) = __gu_tmp.t; \
} }
@ -135,13 +135,12 @@ struct exception_table_entry {
#define __put_user_internal(sr, x, ptr) \ #define __put_user_internal(sr, x, ptr) \
({ \ ({ \
ASM_EXCEPTIONTABLE_VAR(__pu_err); \ ASM_EXCEPTIONTABLE_VAR(__pu_err); \
__typeof__(*(ptr)) __x = (__typeof__(*(ptr)))(x); \
\ \
switch (sizeof(*(ptr))) { \ switch (sizeof(*(ptr))) { \
case 1: __put_user_asm(sr, "stb", __x, ptr); break; \ case 1: __put_user_asm(sr, "stb", x, ptr); break; \
case 2: __put_user_asm(sr, "sth", __x, ptr); break; \ case 2: __put_user_asm(sr, "sth", x, ptr); break; \
case 4: __put_user_asm(sr, "stw", __x, ptr); break; \ case 4: __put_user_asm(sr, "stw", x, ptr); break; \
case 8: STD_USER(sr, __x, ptr); break; \ case 8: STD_USER(sr, x, ptr); break; \
default: BUILD_BUG(); \ default: BUILD_BUG(); \
} \ } \
\ \
@ -150,7 +149,9 @@ struct exception_table_entry {
#define __put_user(x, ptr) \ #define __put_user(x, ptr) \
({ \ ({ \
__put_user_internal("%%sr3,", x, ptr); \ __typeof__(&*(ptr)) __ptr = ptr; \
__typeof__(*(__ptr)) __x = (__typeof__(*(__ptr)))(x); \
__put_user_internal("%%sr3,", __x, __ptr); \
}) })
#define __put_kernel_nofault(dst, src, type, err_label) \ #define __put_kernel_nofault(dst, src, type, err_label) \
@ -180,8 +181,8 @@ struct exception_table_entry {
"1: " stx " %2,0(" sr "%1)\n" \ "1: " stx " %2,0(" sr "%1)\n" \
"9:\n" \ "9:\n" \
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \
: "=r"(__pu_err) \ : "+r"(__pu_err) \
: "r"(ptr), "r"(x), "0"(__pu_err)) : "r"(ptr), "r"(x))
#if !defined(CONFIG_64BIT) #if !defined(CONFIG_64BIT)
@ -193,8 +194,8 @@ struct exception_table_entry {
"9:\n" \ "9:\n" \
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \
: "=r"(__pu_err) \ : "+r"(__pu_err) \
: "r"(ptr), "r"(__val), "0"(__pu_err)); \ : "r"(ptr), "r"(__val)); \
} while (0) } while (0)
#endif /* !defined(CONFIG_64BIT) */ #endif /* !defined(CONFIG_64BIT) */