X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fs390%2Fmm%2Ffault.c;h=d6bd3d4298601b0afbd969253e066922f75549c5;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=9cf3b392ebf55bf761cf4f48010e29954e582cd5;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 9cf3b392e..d6bd3d429 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -25,11 +25,11 @@ #include #include #include +#include #include #include #include -#include #ifndef CONFIG_ARCH_S390X #define __FAIL_ADDR_MASK 0x7ffff000 @@ -126,8 +126,8 @@ static inline int check_user_space(struct pt_regs *regs, int error_code) * Send SIGSEGV to task. This is an external routine * to keep the stack usage of do_page_fault small. */ -static void force_sigsegv(struct pt_regs *regs, unsigned long error_code, - int si_code, unsigned long address) +static void do_sigsegv(struct pt_regs *regs, unsigned long error_code, + int si_code, unsigned long address) { struct siginfo si; @@ -159,7 +159,8 @@ static void force_sigsegv(struct pt_regs *regs, unsigned long error_code, * 11 Page translation -> Not present (nullification) * 3b Region third trans. -> Not present (nullification) */ -extern inline void do_exception(struct pt_regs *regs, unsigned long error_code) +extern inline void +do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection) { struct task_struct *tsk; struct mm_struct *mm; @@ -177,7 +178,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code) * as a special case because the translation exception code * field is not guaranteed to contain valid data in this case. */ - if (error_code == 4 && !(S390_lowcore.trans_exc_code & 4)) { + if (is_protection && !(S390_lowcore.trans_exc_code & 4)) { /* Low-address protection hit in kernel mode means NULL pointer write access in kernel mode. */ @@ -232,7 +233,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code) */ good_area: si_code = SEGV_ACCERR; - if (error_code != 4) { + if (!is_protection) { /* page not present, check vm flags */ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) goto bad_area; @@ -247,7 +248,7 @@ survive: * make sure we exit gracefully rather than endlessly redo * the fault. */ - switch (handle_mm_fault(mm, vma, address, error_code == 4)) { + switch (handle_mm_fault(mm, vma, address, is_protection)) { case VM_FAULT_MINOR: tsk->min_flt++; break; @@ -263,6 +264,11 @@ survive: } up_read(&mm->mmap_sem); + /* + * The instruction that caused the program check will + * be repeated. Don't signal single step via SIGTRAP. + */ + clear_tsk_thread_flag(current, TIF_SINGLE_STEP); return; /* @@ -276,7 +282,7 @@ bad_area: if (regs->psw.mask & PSW_MASK_PSTATE) { tsk->thread.prot_addr = address; tsk->thread.trap_no = error_code; - force_sigsegv(regs, error_code, si_code, address); + do_sigsegv(regs, error_code, si_code, address); return; } @@ -337,28 +343,15 @@ do_sigbus: void do_protection_exception(struct pt_regs *regs, unsigned long error_code) { regs->psw.addr -= (error_code >> 16); - do_exception(regs, 4); + do_exception(regs, 4, 1); } -void do_segment_exception(struct pt_regs *regs, unsigned long error_code) +void do_dat_exception(struct pt_regs *regs, unsigned long error_code) { - do_exception(regs, 0x10); + do_exception(regs, error_code & 0xff, 0); } -void do_page_exception(struct pt_regs *regs, unsigned long error_code) -{ - do_exception(regs, 0x11); -} - -#ifdef CONFIG_ARCH_S390X - -void -do_region_exception(struct pt_regs *regs, unsigned long error_code) -{ - do_exception(regs, 0x3b); -} - -#else /* CONFIG_ARCH_S390X */ +#ifndef CONFIG_ARCH_S390X typedef struct _pseudo_wait_t { struct _pseudo_wait_t *next; @@ -456,6 +449,11 @@ do_pseudo_page_fault(struct pt_regs *regs, unsigned long error_code) wait_struct.next = pseudo_lock_queue; pseudo_lock_queue = &wait_struct; spin_unlock(&pseudo_wait_spinlock); + /* + * The instruction that caused the program check will + * be repeated. Don't signal single step via SIGTRAP. + */ + clear_tsk_thread_flag(current, TIF_SINGLE_STEP); /* go to sleep */ wait_event(wait_struct.queue, wait_struct.resolved); }