aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHelge Deller <deller@gmx.de>2017-04-16 04:00:14 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-04-21 03:31:23 -0400
commita28acecbaf25b0ab71d62b6b64b6bd75f9892bb1 (patch)
treee0a17fb6a21471cc18b009b7bc1a99e2ae59b9d4
parentc10479591869177ae7ac0570b54ace6fbdeb57c2 (diff)
parisc: Fix get_user() for 64-bit value on 32-bit kernel
commit 3f795cef0ecdf9bc980dd058d49bdab4b19af1d3 upstream. This fixes a bug in which the upper 32-bits of a 64-bit value which is read by get_user() was lost on a 32-bit kernel. While touching this code, split out pre-loading of %sr2 space register and clean up code indent. Signed-off-by: Helge Deller <deller@gmx.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--arch/parisc/include/asm/uaccess.h86
1 files changed, 55 insertions, 31 deletions
diff --git a/arch/parisc/include/asm/uaccess.h b/arch/parisc/include/asm/uaccess.h
index 7fcf5128996a..0497ceceeb85 100644
--- a/arch/parisc/include/asm/uaccess.h
+++ b/arch/parisc/include/asm/uaccess.h
@@ -42,10 +42,10 @@ static inline long access_ok(int type, const void __user * addr,
42#define get_user __get_user 42#define get_user __get_user
43 43
44#if !defined(CONFIG_64BIT) 44#if !defined(CONFIG_64BIT)
45#define LDD_USER(ptr) __get_user_asm64(ptr) 45#define LDD_USER(val, ptr) __get_user_asm64(val, ptr)
46#define STD_USER(x, ptr) __put_user_asm64(x, ptr) 46#define STD_USER(x, ptr) __put_user_asm64(x, ptr)
47#else 47#else
48#define LDD_USER(ptr) __get_user_asm("ldd", ptr) 48#define LDD_USER(val, ptr) __get_user_asm(val, "ldd", ptr)
49#define STD_USER(x, ptr) __put_user_asm("std", x, ptr) 49#define STD_USER(x, ptr) __put_user_asm("std", x, ptr)
50#endif 50#endif
51 51
@@ -100,63 +100,87 @@ struct exception_data {
100 " mtsp %0,%%sr2\n\t" \ 100 " mtsp %0,%%sr2\n\t" \
101 : : "r"(get_fs()) : ) 101 : : "r"(get_fs()) : )
102 102
103#define __get_user(x, ptr) \ 103#define __get_user_internal(val, ptr) \
104({ \ 104({ \
105 register long __gu_err __asm__ ("r8") = 0; \ 105 register long __gu_err __asm__ ("r8") = 0; \
106 register long __gu_val; \ 106 \
107 \ 107 switch (sizeof(*(ptr))) { \
108 load_sr2(); \ 108 case 1: __get_user_asm(val, "ldb", ptr); break; \
109 switch (sizeof(*(ptr))) { \ 109 case 2: __get_user_asm(val, "ldh", ptr); break; \
110 case 1: __get_user_asm("ldb", ptr); break; \ 110 case 4: __get_user_asm(val, "ldw", ptr); break; \
111 case 2: __get_user_asm("ldh", ptr); break; \ 111 case 8: LDD_USER(val, ptr); break; \
112 case 4: __get_user_asm("ldw", ptr); break; \ 112 default: BUILD_BUG(); \
113 case 8: LDD_USER(ptr); break; \ 113 } \
114 default: BUILD_BUG(); break; \ 114 \
115 } \ 115 __gu_err; \
116 \
117 (x) = (__force __typeof__(*(ptr))) __gu_val; \
118 __gu_err; \
119}) 116})
120 117
121#define __get_user_asm(ldx, ptr) \ 118#define __get_user(val, ptr) \
119({ \
120 load_sr2(); \
121 __get_user_internal(val, ptr); \
122})
123
124#define __get_user_asm(val, ldx, ptr) \
125{ \
126 register long __gu_val; \
127 \
122 __asm__("1: " ldx " 0(%%sr2,%2),%0\n" \ 128 __asm__("1: " ldx " 0(%%sr2,%2),%0\n" \
123 "9:\n" \ 129 "9:\n" \
124 ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ 130 ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \
125 : "=r"(__gu_val), "=r"(__gu_err) \ 131 : "=r"(__gu_val), "=r"(__gu_err) \
126 : "r"(ptr), "1"(__gu_err)); 132 : "r"(ptr), "1"(__gu_err)); \
133 \
134 (val) = (__force __typeof__(*(ptr))) __gu_val; \
135}
127 136
128#if !defined(CONFIG_64BIT) 137#if !defined(CONFIG_64BIT)
129 138
130#define __get_user_asm64(ptr) \ 139#define __get_user_asm64(val, ptr) \
140{ \
141 union { \
142 unsigned long long l; \
143 __typeof__(*(ptr)) t; \
144 } __gu_tmp; \
145 \
131 __asm__(" copy %%r0,%R0\n" \ 146 __asm__(" copy %%r0,%R0\n" \
132 "1: ldw 0(%%sr2,%2),%0\n" \ 147 "1: ldw 0(%%sr2,%2),%0\n" \
133 "2: ldw 4(%%sr2,%2),%R0\n" \ 148 "2: ldw 4(%%sr2,%2),%R0\n" \
134 "9:\n" \ 149 "9:\n" \
135 ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ 150 ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \
136 ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \ 151 ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \
137 : "=r"(__gu_val), "=r"(__gu_err) \ 152 : "=&r"(__gu_tmp.l), "=r"(__gu_err) \
138 : "r"(ptr), "1"(__gu_err)); 153 : "r"(ptr), "1"(__gu_err)); \
154 \
155 (val) = __gu_tmp.t; \
156}
139 157
140#endif /* !defined(CONFIG_64BIT) */ 158#endif /* !defined(CONFIG_64BIT) */
141 159
142 160
143#define __put_user(x, ptr) \ 161#define __put_user_internal(x, ptr) \
144({ \ 162({ \
145 register long __pu_err __asm__ ("r8") = 0; \ 163 register long __pu_err __asm__ ("r8") = 0; \
146 __typeof__(*(ptr)) __x = (__typeof__(*(ptr)))(x); \ 164 __typeof__(*(ptr)) __x = (__typeof__(*(ptr)))(x); \
147 \ 165 \
148 load_sr2(); \
149 switch (sizeof(*(ptr))) { \ 166 switch (sizeof(*(ptr))) { \
150 case 1: __put_user_asm("stb", __x, ptr); break; \ 167 case 1: __put_user_asm("stb", __x, ptr); break; \
151 case 2: __put_user_asm("sth", __x, ptr); break; \ 168 case 2: __put_user_asm("sth", __x, ptr); break; \
152 case 4: __put_user_asm("stw", __x, ptr); break; \ 169 case 4: __put_user_asm("stw", __x, ptr); break; \
153 case 8: STD_USER(__x, ptr); break; \ 170 case 8: STD_USER(__x, ptr); break; \
154 default: BUILD_BUG(); break; \ 171 default: BUILD_BUG(); \
155 } \ 172 } \
156 \ 173 \
157 __pu_err; \ 174 __pu_err; \
158}) 175})
159 176
177#define __put_user(x, ptr) \
178({ \
179 load_sr2(); \
180 __put_user_internal(x, ptr); \
181})
182
183
160/* 184/*
161 * The "__put_user/kernel_asm()" macros tell gcc they read from memory 185 * The "__put_user/kernel_asm()" macros tell gcc they read from memory
162 * instead of writing. This is because they do not write to any memory 186 * instead of writing. This is because they do not write to any memory