diff options
-rw-r--r-- | arch/s390/mm/fault.c | 72 |
1 files changed, 21 insertions, 51 deletions
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 8bc35183db59..2b76a879a7b5 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c | |||
@@ -26,9 +26,9 @@ | |||
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/hardirq.h> | 27 | #include <linux/hardirq.h> |
28 | #include <linux/kprobes.h> | 28 | #include <linux/kprobes.h> |
29 | #include <linux/uaccess.h> | ||
29 | 30 | ||
30 | #include <asm/system.h> | 31 | #include <asm/system.h> |
31 | #include <asm/uaccess.h> | ||
32 | #include <asm/pgtable.h> | 32 | #include <asm/pgtable.h> |
33 | #include <asm/kdebug.h> | 33 | #include <asm/kdebug.h> |
34 | #include <asm/s390_ext.h> | 34 | #include <asm/s390_ext.h> |
@@ -263,68 +263,38 @@ extern long sys_rt_sigreturn(struct pt_regs *regs); | |||
263 | extern long sys32_sigreturn(struct pt_regs *regs); | 263 | extern long sys32_sigreturn(struct pt_regs *regs); |
264 | extern long sys32_rt_sigreturn(struct pt_regs *regs); | 264 | extern long sys32_rt_sigreturn(struct pt_regs *regs); |
265 | 265 | ||
266 | static inline void do_sigreturn(struct mm_struct *mm, struct pt_regs *regs, | 266 | static int signal_return(struct mm_struct *mm, struct pt_regs *regs, |
267 | int rt) | 267 | unsigned long address, unsigned long error_code) |
268 | { | 268 | { |
269 | u16 instruction; | ||
270 | int rc, compat; | ||
271 | |||
272 | pagefault_disable(); | ||
273 | rc = __get_user(instruction, (u16 __user *) regs->psw.addr); | ||
274 | pagefault_enable(); | ||
275 | if (rc) | ||
276 | return -EFAULT; | ||
277 | |||
269 | up_read(&mm->mmap_sem); | 278 | up_read(&mm->mmap_sem); |
270 | clear_tsk_thread_flag(current, TIF_SINGLE_STEP); | 279 | clear_tsk_thread_flag(current, TIF_SINGLE_STEP); |
271 | #ifdef CONFIG_COMPAT | 280 | #ifdef CONFIG_COMPAT |
272 | if (test_tsk_thread_flag(current, TIF_31BIT)) { | 281 | compat = test_tsk_thread_flag(current, TIF_31BIT); |
273 | if (rt) | 282 | if (compat && instruction == 0x0a77) |
274 | sys32_rt_sigreturn(regs); | 283 | sys32_sigreturn(regs); |
275 | else | 284 | else if (compat && instruction == 0x0aad) |
276 | sys32_sigreturn(regs); | 285 | sys32_rt_sigreturn(regs); |
277 | return; | ||
278 | } | ||
279 | #endif /* CONFIG_COMPAT */ | ||
280 | if (rt) | ||
281 | sys_rt_sigreturn(regs); | ||
282 | else | 286 | else |
287 | #endif | ||
288 | if (instruction == 0x0a77) | ||
283 | sys_sigreturn(regs); | 289 | sys_sigreturn(regs); |
284 | return; | 290 | else if (instruction == 0x0aad) |
285 | } | 291 | sys_rt_sigreturn(regs); |
286 | |||
287 | static int signal_return(struct mm_struct *mm, struct pt_regs *regs, | ||
288 | unsigned long address, unsigned long error_code) | ||
289 | { | ||
290 | pgd_t *pgd; | ||
291 | pmd_t *pmd; | ||
292 | pte_t *pte; | ||
293 | u16 *instruction; | ||
294 | unsigned long pfn, uaddr = regs->psw.addr; | ||
295 | |||
296 | spin_lock(&mm->page_table_lock); | ||
297 | pgd = pgd_offset(mm, uaddr); | ||
298 | if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) | ||
299 | goto out_fault; | ||
300 | pmd = pmd_offset(pgd, uaddr); | ||
301 | if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) | ||
302 | goto out_fault; | ||
303 | pte = pte_offset_map(pmd_offset(pgd_offset(mm, uaddr), uaddr), uaddr); | ||
304 | if (!pte || !pte_present(*pte)) | ||
305 | goto out_fault; | ||
306 | pfn = pte_pfn(*pte); | ||
307 | if (!pfn_valid(pfn)) | ||
308 | goto out_fault; | ||
309 | spin_unlock(&mm->page_table_lock); | ||
310 | |||
311 | instruction = (u16 *) ((pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE-1))); | ||
312 | if (*instruction == 0x0a77) | ||
313 | do_sigreturn(mm, regs, 0); | ||
314 | else if (*instruction == 0x0aad) | ||
315 | do_sigreturn(mm, regs, 1); | ||
316 | else { | 292 | else { |
317 | printk("- XXX - do_exception: task = %s, primary, NO EXEC " | ||
318 | "-> SIGSEGV\n", current->comm); | ||
319 | up_read(&mm->mmap_sem); | ||
320 | current->thread.prot_addr = address; | 293 | current->thread.prot_addr = address; |
321 | current->thread.trap_no = error_code; | 294 | current->thread.trap_no = error_code; |
322 | do_sigsegv(regs, error_code, SEGV_MAPERR, address); | 295 | do_sigsegv(regs, error_code, SEGV_MAPERR, address); |
323 | } | 296 | } |
324 | return 0; | 297 | return 0; |
325 | out_fault: | ||
326 | spin_unlock(&mm->page_table_lock); | ||
327 | return -EFAULT; | ||
328 | } | 298 | } |
329 | #endif /* CONFIG_S390_EXEC_PROTECT */ | 299 | #endif /* CONFIG_S390_EXEC_PROTECT */ |
330 | 300 | ||