diff options
author | Helge Deller <deller@gmx.de> | 2017-04-16 04:00:14 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-04-21 03:31:23 -0400 |
commit | a28acecbaf25b0ab71d62b6b64b6bd75f9892bb1 (patch) | |
tree | e0a17fb6a21471cc18b009b7bc1a99e2ae59b9d4 | |
parent | c10479591869177ae7ac0570b54ace6fbdeb57c2 (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.h | 86 |
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 |