diff options
-rw-r--r-- | arch/sparc64/kernel/sys32.S | 145 | ||||
-rw-r--r-- | arch/sparc64/kernel/traps.c | 24 | ||||
-rw-r--r-- | arch/sparc64/kernel/unaligned.c | 9 | ||||
-rw-r--r-- | arch/sparc64/mm/Makefile | 2 | ||||
-rw-r--r-- | arch/sparc64/mm/extable.c | 80 | ||||
-rw-r--r-- | arch/sparc64/mm/fault.c | 10 | ||||
-rw-r--r-- | include/asm-sparc64/uaccess.h | 17 |
7 files changed, 101 insertions, 186 deletions
diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S index 5f9e4fae612e..4fb99e0bc7c3 100644 --- a/arch/sparc64/kernel/sys32.S +++ b/arch/sparc64/kernel/sys32.S | |||
@@ -158,163 +158,163 @@ sys32_socketcall: /* %o0=call, %o1=args */ | |||
158 | jmpl %g2 + %o0, %g0 | 158 | jmpl %g2 + %o0, %g0 |
159 | nop | 159 | nop |
160 | 160 | ||
161 | /* Each entry is exactly 32 bytes. */ | ||
162 | .align 32 | 161 | .align 32 |
163 | __socketcall_table_begin: | 162 | __socketcall_table_begin: |
163 | |||
164 | /* Each entry is exactly 32 bytes. */ | ||
164 | do_sys_socket: /* sys_socket(int, int, int) */ | 165 | do_sys_socket: /* sys_socket(int, int, int) */ |
165 | ldswa [%o1 + 0x0] %asi, %o0 | 166 | 1: ldswa [%o1 + 0x0] %asi, %o0 |
166 | sethi %hi(sys_socket), %g1 | 167 | sethi %hi(sys_socket), %g1 |
167 | ldswa [%o1 + 0x8] %asi, %o2 | 168 | 2: ldswa [%o1 + 0x8] %asi, %o2 |
168 | jmpl %g1 + %lo(sys_socket), %g0 | 169 | jmpl %g1 + %lo(sys_socket), %g0 |
169 | ldswa [%o1 + 0x4] %asi, %o1 | 170 | 3: ldswa [%o1 + 0x4] %asi, %o1 |
170 | nop | 171 | nop |
171 | nop | 172 | nop |
172 | nop | 173 | nop |
173 | do_sys_bind: /* sys_bind(int fd, struct sockaddr *, int) */ | 174 | do_sys_bind: /* sys_bind(int fd, struct sockaddr *, int) */ |
174 | ldswa [%o1 + 0x0] %asi, %o0 | 175 | 4: ldswa [%o1 + 0x0] %asi, %o0 |
175 | sethi %hi(sys_bind), %g1 | 176 | sethi %hi(sys_bind), %g1 |
176 | ldswa [%o1 + 0x8] %asi, %o2 | 177 | 5: ldswa [%o1 + 0x8] %asi, %o2 |
177 | jmpl %g1 + %lo(sys_bind), %g0 | 178 | jmpl %g1 + %lo(sys_bind), %g0 |
178 | lduwa [%o1 + 0x4] %asi, %o1 | 179 | 6: lduwa [%o1 + 0x4] %asi, %o1 |
179 | nop | 180 | nop |
180 | nop | 181 | nop |
181 | nop | 182 | nop |
182 | do_sys_connect: /* sys_connect(int, struct sockaddr *, int) */ | 183 | do_sys_connect: /* sys_connect(int, struct sockaddr *, int) */ |
183 | ldswa [%o1 + 0x0] %asi, %o0 | 184 | 7: ldswa [%o1 + 0x0] %asi, %o0 |
184 | sethi %hi(sys_connect), %g1 | 185 | sethi %hi(sys_connect), %g1 |
185 | ldswa [%o1 + 0x8] %asi, %o2 | 186 | 8: ldswa [%o1 + 0x8] %asi, %o2 |
186 | jmpl %g1 + %lo(sys_connect), %g0 | 187 | jmpl %g1 + %lo(sys_connect), %g0 |
187 | lduwa [%o1 + 0x4] %asi, %o1 | 188 | 9: lduwa [%o1 + 0x4] %asi, %o1 |
188 | nop | 189 | nop |
189 | nop | 190 | nop |
190 | nop | 191 | nop |
191 | do_sys_listen: /* sys_listen(int, int) */ | 192 | do_sys_listen: /* sys_listen(int, int) */ |
192 | ldswa [%o1 + 0x0] %asi, %o0 | 193 | 10: ldswa [%o1 + 0x0] %asi, %o0 |
193 | sethi %hi(sys_listen), %g1 | 194 | sethi %hi(sys_listen), %g1 |
194 | jmpl %g1 + %lo(sys_listen), %g0 | 195 | jmpl %g1 + %lo(sys_listen), %g0 |
195 | ldswa [%o1 + 0x4] %asi, %o1 | 196 | 11: ldswa [%o1 + 0x4] %asi, %o1 |
196 | nop | 197 | nop |
197 | nop | 198 | nop |
198 | nop | 199 | nop |
199 | nop | 200 | nop |
200 | do_sys_accept: /* sys_accept(int, struct sockaddr *, int *) */ | 201 | do_sys_accept: /* sys_accept(int, struct sockaddr *, int *) */ |
201 | ldswa [%o1 + 0x0] %asi, %o0 | 202 | 12: ldswa [%o1 + 0x0] %asi, %o0 |
202 | sethi %hi(sys_accept), %g1 | 203 | sethi %hi(sys_accept), %g1 |
203 | lduwa [%o1 + 0x8] %asi, %o2 | 204 | 13: lduwa [%o1 + 0x8] %asi, %o2 |
204 | jmpl %g1 + %lo(sys_accept), %g0 | 205 | jmpl %g1 + %lo(sys_accept), %g0 |
205 | lduwa [%o1 + 0x4] %asi, %o1 | 206 | 14: lduwa [%o1 + 0x4] %asi, %o1 |
206 | nop | 207 | nop |
207 | nop | 208 | nop |
208 | nop | 209 | nop |
209 | do_sys_getsockname: /* sys_getsockname(int, struct sockaddr *, int *) */ | 210 | do_sys_getsockname: /* sys_getsockname(int, struct sockaddr *, int *) */ |
210 | ldswa [%o1 + 0x0] %asi, %o0 | 211 | 15: ldswa [%o1 + 0x0] %asi, %o0 |
211 | sethi %hi(sys_getsockname), %g1 | 212 | sethi %hi(sys_getsockname), %g1 |
212 | lduwa [%o1 + 0x8] %asi, %o2 | 213 | 16: lduwa [%o1 + 0x8] %asi, %o2 |
213 | jmpl %g1 + %lo(sys_getsockname), %g0 | 214 | jmpl %g1 + %lo(sys_getsockname), %g0 |
214 | lduwa [%o1 + 0x4] %asi, %o1 | 215 | 17: lduwa [%o1 + 0x4] %asi, %o1 |
215 | nop | 216 | nop |
216 | nop | 217 | nop |
217 | nop | 218 | nop |
218 | do_sys_getpeername: /* sys_getpeername(int, struct sockaddr *, int *) */ | 219 | do_sys_getpeername: /* sys_getpeername(int, struct sockaddr *, int *) */ |
219 | ldswa [%o1 + 0x0] %asi, %o0 | 220 | 18: ldswa [%o1 + 0x0] %asi, %o0 |
220 | sethi %hi(sys_getpeername), %g1 | 221 | sethi %hi(sys_getpeername), %g1 |
221 | lduwa [%o1 + 0x8] %asi, %o2 | 222 | 19: lduwa [%o1 + 0x8] %asi, %o2 |
222 | jmpl %g1 + %lo(sys_getpeername), %g0 | 223 | jmpl %g1 + %lo(sys_getpeername), %g0 |
223 | lduwa [%o1 + 0x4] %asi, %o1 | 224 | 20: lduwa [%o1 + 0x4] %asi, %o1 |
224 | nop | 225 | nop |
225 | nop | 226 | nop |
226 | nop | 227 | nop |
227 | do_sys_socketpair: /* sys_socketpair(int, int, int, int *) */ | 228 | do_sys_socketpair: /* sys_socketpair(int, int, int, int *) */ |
228 | ldswa [%o1 + 0x0] %asi, %o0 | 229 | 21: ldswa [%o1 + 0x0] %asi, %o0 |
229 | sethi %hi(sys_socketpair), %g1 | 230 | sethi %hi(sys_socketpair), %g1 |
230 | ldswa [%o1 + 0x8] %asi, %o2 | 231 | 22: ldswa [%o1 + 0x8] %asi, %o2 |
231 | lduwa [%o1 + 0xc] %asi, %o3 | 232 | 23: lduwa [%o1 + 0xc] %asi, %o3 |
232 | jmpl %g1 + %lo(sys_socketpair), %g0 | 233 | jmpl %g1 + %lo(sys_socketpair), %g0 |
233 | ldswa [%o1 + 0x4] %asi, %o1 | 234 | 24: ldswa [%o1 + 0x4] %asi, %o1 |
234 | nop | 235 | nop |
235 | nop | 236 | nop |
236 | do_sys_send: /* sys_send(int, void *, size_t, unsigned int) */ | 237 | do_sys_send: /* sys_send(int, void *, size_t, unsigned int) */ |
237 | ldswa [%o1 + 0x0] %asi, %o0 | 238 | 25: ldswa [%o1 + 0x0] %asi, %o0 |
238 | sethi %hi(sys_send), %g1 | 239 | sethi %hi(sys_send), %g1 |
239 | lduwa [%o1 + 0x8] %asi, %o2 | 240 | 26: lduwa [%o1 + 0x8] %asi, %o2 |
240 | lduwa [%o1 + 0xc] %asi, %o3 | 241 | 27: lduwa [%o1 + 0xc] %asi, %o3 |
241 | jmpl %g1 + %lo(sys_send), %g0 | 242 | jmpl %g1 + %lo(sys_send), %g0 |
242 | lduwa [%o1 + 0x4] %asi, %o1 | 243 | 28: lduwa [%o1 + 0x4] %asi, %o1 |
243 | nop | 244 | nop |
244 | nop | 245 | nop |
245 | do_sys_recv: /* sys_recv(int, void *, size_t, unsigned int) */ | 246 | do_sys_recv: /* sys_recv(int, void *, size_t, unsigned int) */ |
246 | ldswa [%o1 + 0x0] %asi, %o0 | 247 | 29: ldswa [%o1 + 0x0] %asi, %o0 |
247 | sethi %hi(sys_recv), %g1 | 248 | sethi %hi(sys_recv), %g1 |
248 | lduwa [%o1 + 0x8] %asi, %o2 | 249 | 30: lduwa [%o1 + 0x8] %asi, %o2 |
249 | lduwa [%o1 + 0xc] %asi, %o3 | 250 | 31: lduwa [%o1 + 0xc] %asi, %o3 |
250 | jmpl %g1 + %lo(sys_recv), %g0 | 251 | jmpl %g1 + %lo(sys_recv), %g0 |
251 | lduwa [%o1 + 0x4] %asi, %o1 | 252 | 32: lduwa [%o1 + 0x4] %asi, %o1 |
252 | nop | 253 | nop |
253 | nop | 254 | nop |
254 | do_sys_sendto: /* sys_sendto(int, u32, compat_size_t, unsigned int, u32, int) */ | 255 | do_sys_sendto: /* sys_sendto(int, u32, compat_size_t, unsigned int, u32, int) */ |
255 | ldswa [%o1 + 0x0] %asi, %o0 | 256 | 33: ldswa [%o1 + 0x0] %asi, %o0 |
256 | sethi %hi(sys_sendto), %g1 | 257 | sethi %hi(sys_sendto), %g1 |
257 | lduwa [%o1 + 0x8] %asi, %o2 | 258 | 34: lduwa [%o1 + 0x8] %asi, %o2 |
258 | lduwa [%o1 + 0xc] %asi, %o3 | 259 | 35: lduwa [%o1 + 0xc] %asi, %o3 |
259 | lduwa [%o1 + 0x10] %asi, %o4 | 260 | 36: lduwa [%o1 + 0x10] %asi, %o4 |
260 | ldswa [%o1 + 0x14] %asi, %o5 | 261 | 37: ldswa [%o1 + 0x14] %asi, %o5 |
261 | jmpl %g1 + %lo(sys_sendto), %g0 | 262 | jmpl %g1 + %lo(sys_sendto), %g0 |
262 | lduwa [%o1 + 0x4] %asi, %o1 | 263 | 38: lduwa [%o1 + 0x4] %asi, %o1 |
263 | do_sys_recvfrom: /* sys_recvfrom(int, u32, compat_size_t, unsigned int, u32, u32) */ | 264 | do_sys_recvfrom: /* sys_recvfrom(int, u32, compat_size_t, unsigned int, u32, u32) */ |
264 | ldswa [%o1 + 0x0] %asi, %o0 | 265 | 39: ldswa [%o1 + 0x0] %asi, %o0 |
265 | sethi %hi(sys_recvfrom), %g1 | 266 | sethi %hi(sys_recvfrom), %g1 |
266 | lduwa [%o1 + 0x8] %asi, %o2 | 267 | 40: lduwa [%o1 + 0x8] %asi, %o2 |
267 | lduwa [%o1 + 0xc] %asi, %o3 | 268 | 41: lduwa [%o1 + 0xc] %asi, %o3 |
268 | lduwa [%o1 + 0x10] %asi, %o4 | 269 | 42: lduwa [%o1 + 0x10] %asi, %o4 |
269 | lduwa [%o1 + 0x14] %asi, %o5 | 270 | 43: lduwa [%o1 + 0x14] %asi, %o5 |
270 | jmpl %g1 + %lo(sys_recvfrom), %g0 | 271 | jmpl %g1 + %lo(sys_recvfrom), %g0 |
271 | lduwa [%o1 + 0x4] %asi, %o1 | 272 | 44: lduwa [%o1 + 0x4] %asi, %o1 |
272 | do_sys_shutdown: /* sys_shutdown(int, int) */ | 273 | do_sys_shutdown: /* sys_shutdown(int, int) */ |
273 | ldswa [%o1 + 0x0] %asi, %o0 | 274 | 45: ldswa [%o1 + 0x0] %asi, %o0 |
274 | sethi %hi(sys_shutdown), %g1 | 275 | sethi %hi(sys_shutdown), %g1 |
275 | jmpl %g1 + %lo(sys_shutdown), %g0 | 276 | jmpl %g1 + %lo(sys_shutdown), %g0 |
276 | ldswa [%o1 + 0x4] %asi, %o1 | 277 | 46: ldswa [%o1 + 0x4] %asi, %o1 |
277 | nop | 278 | nop |
278 | nop | 279 | nop |
279 | nop | 280 | nop |
280 | nop | 281 | nop |
281 | do_sys_setsockopt: /* compat_sys_setsockopt(int, int, int, char *, int) */ | 282 | do_sys_setsockopt: /* compat_sys_setsockopt(int, int, int, char *, int) */ |
282 | ldswa [%o1 + 0x0] %asi, %o0 | 283 | 47: ldswa [%o1 + 0x0] %asi, %o0 |
283 | sethi %hi(compat_sys_setsockopt), %g1 | 284 | sethi %hi(compat_sys_setsockopt), %g1 |
284 | ldswa [%o1 + 0x8] %asi, %o2 | 285 | 48: ldswa [%o1 + 0x8] %asi, %o2 |
285 | lduwa [%o1 + 0xc] %asi, %o3 | 286 | 49: lduwa [%o1 + 0xc] %asi, %o3 |
286 | ldswa [%o1 + 0x10] %asi, %o4 | 287 | 50: ldswa [%o1 + 0x10] %asi, %o4 |
287 | jmpl %g1 + %lo(compat_sys_setsockopt), %g0 | 288 | jmpl %g1 + %lo(compat_sys_setsockopt), %g0 |
288 | ldswa [%o1 + 0x4] %asi, %o1 | 289 | 51: ldswa [%o1 + 0x4] %asi, %o1 |
289 | nop | 290 | nop |
290 | do_sys_getsockopt: /* compat_sys_getsockopt(int, int, int, u32, u32) */ | 291 | do_sys_getsockopt: /* compat_sys_getsockopt(int, int, int, u32, u32) */ |
291 | ldswa [%o1 + 0x0] %asi, %o0 | 292 | 52: ldswa [%o1 + 0x0] %asi, %o0 |
292 | sethi %hi(compat_sys_getsockopt), %g1 | 293 | sethi %hi(compat_sys_getsockopt), %g1 |
293 | ldswa [%o1 + 0x8] %asi, %o2 | 294 | 53: ldswa [%o1 + 0x8] %asi, %o2 |
294 | lduwa [%o1 + 0xc] %asi, %o3 | 295 | 54: lduwa [%o1 + 0xc] %asi, %o3 |
295 | lduwa [%o1 + 0x10] %asi, %o4 | 296 | 55: lduwa [%o1 + 0x10] %asi, %o4 |
296 | jmpl %g1 + %lo(compat_sys_getsockopt), %g0 | 297 | jmpl %g1 + %lo(compat_sys_getsockopt), %g0 |
297 | ldswa [%o1 + 0x4] %asi, %o1 | 298 | 56: ldswa [%o1 + 0x4] %asi, %o1 |
298 | nop | 299 | nop |
299 | do_sys_sendmsg: /* compat_sys_sendmsg(int, struct compat_msghdr *, unsigned int) */ | 300 | do_sys_sendmsg: /* compat_sys_sendmsg(int, struct compat_msghdr *, unsigned int) */ |
300 | ldswa [%o1 + 0x0] %asi, %o0 | 301 | 57: ldswa [%o1 + 0x0] %asi, %o0 |
301 | sethi %hi(compat_sys_sendmsg), %g1 | 302 | sethi %hi(compat_sys_sendmsg), %g1 |
302 | lduwa [%o1 + 0x8] %asi, %o2 | 303 | 58: lduwa [%o1 + 0x8] %asi, %o2 |
303 | jmpl %g1 + %lo(compat_sys_sendmsg), %g0 | 304 | jmpl %g1 + %lo(compat_sys_sendmsg), %g0 |
304 | lduwa [%o1 + 0x4] %asi, %o1 | 305 | 59: lduwa [%o1 + 0x4] %asi, %o1 |
305 | nop | 306 | nop |
306 | nop | 307 | nop |
307 | nop | 308 | nop |
308 | do_sys_recvmsg: /* compat_sys_recvmsg(int, struct compat_msghdr *, unsigned int) */ | 309 | do_sys_recvmsg: /* compat_sys_recvmsg(int, struct compat_msghdr *, unsigned int) */ |
309 | ldswa [%o1 + 0x0] %asi, %o0 | 310 | 60: ldswa [%o1 + 0x0] %asi, %o0 |
310 | sethi %hi(compat_sys_recvmsg), %g1 | 311 | sethi %hi(compat_sys_recvmsg), %g1 |
311 | lduwa [%o1 + 0x8] %asi, %o2 | 312 | 61: lduwa [%o1 + 0x8] %asi, %o2 |
312 | jmpl %g1 + %lo(compat_sys_recvmsg), %g0 | 313 | jmpl %g1 + %lo(compat_sys_recvmsg), %g0 |
313 | lduwa [%o1 + 0x4] %asi, %o1 | 314 | 62: lduwa [%o1 + 0x4] %asi, %o1 |
314 | nop | 315 | nop |
315 | nop | 316 | nop |
316 | nop | 317 | nop |
317 | __socketcall_table_end: | ||
318 | 318 | ||
319 | do_einval: | 319 | do_einval: |
320 | retl | 320 | retl |
@@ -325,5 +325,20 @@ do_efault: | |||
325 | 325 | ||
326 | .section __ex_table | 326 | .section __ex_table |
327 | .align 4 | 327 | .align 4 |
328 | .word __socketcall_table_begin, 0, __socketcall_table_end, do_efault | 328 | .word 1b, do_efault, 2b, do_efault, 3b, do_efault, 4b, do_efault |
329 | .word 5b, do_efault, 6b, do_efault, 7b, do_efault, 8b, do_efault | ||
330 | .word 9b, do_efault, 10b, do_efault, 11b, do_efault, 12b, do_efault | ||
331 | .word 13b, do_efault, 14b, do_efault, 15b, do_efault, 16b, do_efault | ||
332 | .word 17b, do_efault, 18b, do_efault, 19b, do_efault, 20b, do_efault | ||
333 | .word 21b, do_efault, 22b, do_efault, 23b, do_efault, 24b, do_efault | ||
334 | .word 25b, do_efault, 26b, do_efault, 27b, do_efault, 28b, do_efault | ||
335 | .word 29b, do_efault, 30b, do_efault, 31b, do_efault, 32b, do_efault | ||
336 | .word 33b, do_efault, 34b, do_efault, 35b, do_efault, 36b, do_efault | ||
337 | .word 37b, do_efault, 38b, do_efault, 39b, do_efault, 40b, do_efault | ||
338 | .word 41b, do_efault, 42b, do_efault, 43b, do_efault, 44b, do_efault | ||
339 | .word 45b, do_efault, 46b, do_efault, 47b, do_efault, 48b, do_efault | ||
340 | .word 49b, do_efault, 50b, do_efault, 51b, do_efault, 52b, do_efault | ||
341 | .word 53b, do_efault, 54b, do_efault, 55b, do_efault, 56b, do_efault | ||
342 | .word 57b, do_efault, 58b, do_efault, 59b, do_efault, 60b, do_efault | ||
343 | .word 61b, do_efault, 62b, do_efault | ||
329 | .previous | 344 | .previous |
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index f8e7005fede9..1aa15990f5af 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c | |||
@@ -189,19 +189,18 @@ void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, un | |||
189 | 189 | ||
190 | if (regs->tstate & TSTATE_PRIV) { | 190 | if (regs->tstate & TSTATE_PRIV) { |
191 | /* Test if this comes from uaccess places. */ | 191 | /* Test if this comes from uaccess places. */ |
192 | unsigned long fixup; | 192 | const struct exception_table_entry *entry; |
193 | unsigned long g2 = regs->u_regs[UREG_G2]; | ||
194 | 193 | ||
195 | if ((fixup = search_extables_range(regs->tpc, &g2))) { | 194 | entry = search_exception_tables(regs->tpc); |
196 | /* Ouch, somebody is trying ugly VM hole tricks on us... */ | 195 | if (entry) { |
196 | /* Ouch, somebody is trying VM hole tricks on us... */ | ||
197 | #ifdef DEBUG_EXCEPTIONS | 197 | #ifdef DEBUG_EXCEPTIONS |
198 | printk("Exception: PC<%016lx> faddr<UNKNOWN>\n", regs->tpc); | 198 | printk("Exception: PC<%016lx> faddr<UNKNOWN>\n", regs->tpc); |
199 | printk("EX_TABLE: insn<%016lx> fixup<%016lx> " | 199 | printk("EX_TABLE: insn<%016lx> fixup<%016lx>\n", |
200 | "g2<%016lx>\n", regs->tpc, fixup, g2); | 200 | regs->tpc, entry->fixup); |
201 | #endif | 201 | #endif |
202 | regs->tpc = fixup; | 202 | regs->tpc = entry->fixup; |
203 | regs->tnpc = regs->tpc + 4; | 203 | regs->tnpc = regs->tpc + 4; |
204 | regs->u_regs[UREG_G2] = g2; | ||
205 | return; | 204 | return; |
206 | } | 205 | } |
207 | /* Shit... */ | 206 | /* Shit... */ |
@@ -1610,10 +1609,10 @@ void cheetah_deferred_handler(struct pt_regs *regs, unsigned long afsr, unsigned | |||
1610 | /* OK, usermode access. */ | 1609 | /* OK, usermode access. */ |
1611 | recoverable = 1; | 1610 | recoverable = 1; |
1612 | } else { | 1611 | } else { |
1613 | unsigned long g2 = regs->u_regs[UREG_G2]; | 1612 | const struct exception_table_entry *entry; |
1614 | unsigned long fixup = search_extables_range(regs->tpc, &g2); | ||
1615 | 1613 | ||
1616 | if (fixup != 0UL) { | 1614 | entry = search_exception_tables(regs->tpc); |
1615 | if (entry) { | ||
1617 | /* OK, kernel access to userspace. */ | 1616 | /* OK, kernel access to userspace. */ |
1618 | recoverable = 1; | 1617 | recoverable = 1; |
1619 | 1618 | ||
@@ -1632,9 +1631,8 @@ void cheetah_deferred_handler(struct pt_regs *regs, unsigned long afsr, unsigned | |||
1632 | * recoverable condition. | 1631 | * recoverable condition. |
1633 | */ | 1632 | */ |
1634 | if (recoverable) { | 1633 | if (recoverable) { |
1635 | regs->tpc = fixup; | 1634 | regs->tpc = entry->fixup; |
1636 | regs->tnpc = regs->tpc + 4; | 1635 | regs->tnpc = regs->tpc + 4; |
1637 | regs->u_regs[UREG_G2] = g2; | ||
1638 | } | 1636 | } |
1639 | } | 1637 | } |
1640 | } | 1638 | } |
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c index 02af08ffec8f..9d6be20f4125 100644 --- a/arch/sparc64/kernel/unaligned.c +++ b/arch/sparc64/kernel/unaligned.c | |||
@@ -246,10 +246,10 @@ void kernel_mna_trap_fault(void) | |||
246 | { | 246 | { |
247 | struct pt_regs *regs = current_thread_info()->kern_una_regs; | 247 | struct pt_regs *regs = current_thread_info()->kern_una_regs; |
248 | unsigned int insn = current_thread_info()->kern_una_insn; | 248 | unsigned int insn = current_thread_info()->kern_una_insn; |
249 | unsigned long g2 = regs->u_regs[UREG_G2]; | 249 | const struct exception_table_entry *entry; |
250 | unsigned long fixup = search_extables_range(regs->tpc, &g2); | ||
251 | 250 | ||
252 | if (!fixup) { | 251 | entry = search_exception_tables(regs->tpc); |
252 | if (!entry) { | ||
253 | unsigned long address; | 253 | unsigned long address; |
254 | 254 | ||
255 | address = compute_effective_address(regs, insn, | 255 | address = compute_effective_address(regs, insn, |
@@ -270,9 +270,8 @@ void kernel_mna_trap_fault(void) | |||
270 | die_if_kernel("Oops", regs); | 270 | die_if_kernel("Oops", regs); |
271 | /* Not reached */ | 271 | /* Not reached */ |
272 | } | 272 | } |
273 | regs->tpc = fixup; | 273 | regs->tpc = entry->fixup; |
274 | regs->tnpc = regs->tpc + 4; | 274 | regs->tnpc = regs->tpc + 4; |
275 | regs->u_regs [UREG_G2] = g2; | ||
276 | 275 | ||
277 | regs->tstate &= ~TSTATE_ASI; | 276 | regs->tstate &= ~TSTATE_ASI; |
278 | regs->tstate |= (ASI_AIUS << 24UL); | 277 | regs->tstate |= (ASI_AIUS << 24UL); |
diff --git a/arch/sparc64/mm/Makefile b/arch/sparc64/mm/Makefile index cda87333a77b..9d0960e69f48 100644 --- a/arch/sparc64/mm/Makefile +++ b/arch/sparc64/mm/Makefile | |||
@@ -5,6 +5,6 @@ | |||
5 | EXTRA_AFLAGS := -ansi | 5 | EXTRA_AFLAGS := -ansi |
6 | EXTRA_CFLAGS := -Werror | 6 | EXTRA_CFLAGS := -Werror |
7 | 7 | ||
8 | obj-y := ultra.o tlb.o fault.o init.o generic.o extable.o | 8 | obj-y := ultra.o tlb.o fault.o init.o generic.o |
9 | 9 | ||
10 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o | 10 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o |
diff --git a/arch/sparc64/mm/extable.c b/arch/sparc64/mm/extable.c deleted file mode 100644 index ec334297ff4f..000000000000 --- a/arch/sparc64/mm/extable.c +++ /dev/null | |||
@@ -1,80 +0,0 @@ | |||
1 | /* | ||
2 | * linux/arch/sparc64/mm/extable.c | ||
3 | */ | ||
4 | |||
5 | #include <linux/config.h> | ||
6 | #include <linux/module.h> | ||
7 | #include <asm/uaccess.h> | ||
8 | |||
9 | extern const struct exception_table_entry __start___ex_table[]; | ||
10 | extern const struct exception_table_entry __stop___ex_table[]; | ||
11 | |||
12 | void sort_extable(struct exception_table_entry *start, | ||
13 | struct exception_table_entry *finish) | ||
14 | { | ||
15 | } | ||
16 | |||
17 | /* Caller knows they are in a range if ret->fixup == 0 */ | ||
18 | const struct exception_table_entry * | ||
19 | search_extable(const struct exception_table_entry *start, | ||
20 | const struct exception_table_entry *last, | ||
21 | unsigned long value) | ||
22 | { | ||
23 | const struct exception_table_entry *walk; | ||
24 | |||
25 | /* Single insn entries are encoded as: | ||
26 | * word 1: insn address | ||
27 | * word 2: fixup code address | ||
28 | * | ||
29 | * Range entries are encoded as: | ||
30 | * word 1: first insn address | ||
31 | * word 2: 0 | ||
32 | * word 3: last insn address + 4 bytes | ||
33 | * word 4: fixup code address | ||
34 | * | ||
35 | * See asm/uaccess.h for more details. | ||
36 | */ | ||
37 | |||
38 | /* 1. Try to find an exact match. */ | ||
39 | for (walk = start; walk <= last; walk++) { | ||
40 | if (walk->fixup == 0) { | ||
41 | /* A range entry, skip both parts. */ | ||
42 | walk++; | ||
43 | continue; | ||
44 | } | ||
45 | |||
46 | if (walk->insn == value) | ||
47 | return walk; | ||
48 | } | ||
49 | |||
50 | /* 2. Try to find a range match. */ | ||
51 | for (walk = start; walk <= (last - 1); walk++) { | ||
52 | if (walk->fixup) | ||
53 | continue; | ||
54 | |||
55 | if (walk[0].insn <= value && walk[1].insn > value) | ||
56 | return walk; | ||
57 | |||
58 | walk++; | ||
59 | } | ||
60 | |||
61 | return NULL; | ||
62 | } | ||
63 | |||
64 | /* Special extable search, which handles ranges. Returns fixup */ | ||
65 | unsigned long search_extables_range(unsigned long addr, unsigned long *g2) | ||
66 | { | ||
67 | const struct exception_table_entry *entry; | ||
68 | |||
69 | entry = search_exception_tables(addr); | ||
70 | if (!entry) | ||
71 | return 0; | ||
72 | |||
73 | /* Inside range? Fix g2 and return correct fixup */ | ||
74 | if (!entry->fixup) { | ||
75 | *g2 = (addr - entry->insn) / 4; | ||
76 | return (entry + 1)->fixup; | ||
77 | } | ||
78 | |||
79 | return entry->fixup; | ||
80 | } | ||
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index db1e3310e907..59dc9a2ece5a 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c | |||
@@ -242,7 +242,6 @@ static unsigned int get_fault_insn(struct pt_regs *regs, unsigned int insn) | |||
242 | static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code, | 242 | static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code, |
243 | unsigned int insn, unsigned long address) | 243 | unsigned int insn, unsigned long address) |
244 | { | 244 | { |
245 | unsigned long g2; | ||
246 | unsigned char asi = ASI_P; | 245 | unsigned char asi = ASI_P; |
247 | 246 | ||
248 | if ((!insn) && (regs->tstate & TSTATE_PRIV)) | 247 | if ((!insn) && (regs->tstate & TSTATE_PRIV)) |
@@ -273,11 +272,9 @@ static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code, | |||
273 | } | 272 | } |
274 | } | 273 | } |
275 | 274 | ||
276 | g2 = regs->u_regs[UREG_G2]; | ||
277 | |||
278 | /* Is this in ex_table? */ | 275 | /* Is this in ex_table? */ |
279 | if (regs->tstate & TSTATE_PRIV) { | 276 | if (regs->tstate & TSTATE_PRIV) { |
280 | unsigned long fixup; | 277 | const struct exception_table_entry *entry; |
281 | 278 | ||
282 | if (asi == ASI_P && (insn & 0xc0800000) == 0xc0800000) { | 279 | if (asi == ASI_P && (insn & 0xc0800000) == 0xc0800000) { |
283 | if (insn & 0x2000) | 280 | if (insn & 0x2000) |
@@ -288,10 +285,9 @@ static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code, | |||
288 | 285 | ||
289 | /* Look in asi.h: All _S asis have LS bit set */ | 286 | /* Look in asi.h: All _S asis have LS bit set */ |
290 | if ((asi & 0x1) && | 287 | if ((asi & 0x1) && |
291 | (fixup = search_extables_range(regs->tpc, &g2))) { | 288 | (entry = search_exception_tables(regs->tpc))) { |
292 | regs->tpc = fixup; | 289 | regs->tpc = entry->fixup; |
293 | regs->tnpc = regs->tpc + 4; | 290 | regs->tnpc = regs->tpc + 4; |
294 | regs->u_regs[UREG_G2] = g2; | ||
295 | return; | 291 | return; |
296 | } | 292 | } |
297 | } else { | 293 | } else { |
diff --git a/include/asm-sparc64/uaccess.h b/include/asm-sparc64/uaccess.h index 80a65d7e3dbf..c099aa339784 100644 --- a/include/asm-sparc64/uaccess.h +++ b/include/asm-sparc64/uaccess.h | |||
@@ -70,25 +70,12 @@ static inline int access_ok(int type, const void __user * addr, unsigned long si | |||
70 | * with the main instruction path. This means when everything is well, | 70 | * with the main instruction path. This means when everything is well, |
71 | * we don't even have to jump over them. Further, they do not intrude | 71 | * we don't even have to jump over them. Further, they do not intrude |
72 | * on our cache or tlb entries. | 72 | * on our cache or tlb entries. |
73 | * | ||
74 | * There is a special way how to put a range of potentially faulting | ||
75 | * insns (like twenty ldd/std's with now intervening other instructions) | ||
76 | * You specify address of first in insn and 0 in fixup and in the next | ||
77 | * exception_table_entry you specify last potentially faulting insn + 1 | ||
78 | * and in fixup the routine which should handle the fault. | ||
79 | * That fixup code will get | ||
80 | * (faulting_insn_address - first_insn_in_the_range_address)/4 | ||
81 | * in %g2 (ie. index of the faulting instruction in the range). | ||
82 | */ | 73 | */ |
83 | 74 | ||
84 | struct exception_table_entry | 75 | struct exception_table_entry { |
85 | { | 76 | unsigned int insn, fixup; |
86 | unsigned insn, fixup; | ||
87 | }; | 77 | }; |
88 | 78 | ||
89 | /* Special exable search, which handles ranges. Returns fixup */ | ||
90 | unsigned long search_extables_range(unsigned long addr, unsigned long *g2); | ||
91 | |||
92 | extern void __ret_efault(void); | 79 | extern void __ret_efault(void); |
93 | 80 | ||
94 | /* Uh, these should become the main single-value transfer routines.. | 81 | /* Uh, these should become the main single-value transfer routines.. |