diff options
Diffstat (limited to 'arch/parisc/mm/fault.c')
| -rw-r--r-- | arch/parisc/mm/fault.c | 42 | 
1 files changed, 32 insertions, 10 deletions
diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index d10d27a720c0..7584a5df0fa4 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -142,6 +142,12 @@ int fixup_exception(struct pt_regs *regs)  {  	const struct exception_table_entry *fix; +	/* If we only stored 32bit addresses in the exception table we can drop +	 * out if we faulted on a 64bit address. */ +	if ((sizeof(regs->iaoq[0]) > sizeof(fix->insn)) +		&& (regs->iaoq[0] >> 32)) +			return 0; +  	fix = search_exception_tables(regs->iaoq[0]);  	if (fix) {  		struct exception_data *d; @@ -171,17 +177,25 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,  			      unsigned long address)  {  	struct vm_area_struct *vma, *prev_vma; -	struct task_struct *tsk = current; -	struct mm_struct *mm = tsk->mm; +	struct task_struct *tsk; +	struct mm_struct *mm;  	unsigned long acc_type;  	int fault; -	unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; +	unsigned int flags; + +	if (in_atomic()) +		goto no_context; -	if (in_atomic() || !mm) +	tsk = current; +	mm = tsk->mm; +	if (!mm)  		goto no_context; +	flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;  	if (user_mode(regs))  		flags |= FAULT_FLAG_USER; + +	acc_type = parisc_acctyp(code, regs->iir);  	if (acc_type & VM_WRITE)  		flags |= FAULT_FLAG_WRITE;  retry: @@ -196,8 +210,6 @@ retry:  good_area: -	acc_type = parisc_acctyp(code,regs->iir); -  	if ((vma->vm_flags & acc_type) != acc_type)  		goto bad_area; @@ -268,12 +280,22 @@ bad_area:  		}  		show_regs(regs);  #endif -		/* FIXME: actually we need to get the signo and code correct */ -		si.si_signo = SIGSEGV; +		switch (code) { +		case 15:	/* Data TLB miss fault/Data page fault */ +		case 17:	/* NA data TLB miss / page fault */ +		case 18:	/* Unaligned access - PCXS only */ +			si.si_signo = SIGBUS; +			si.si_code = BUS_ADRERR; +			break; +		case 16:	/* Non-access instruction TLB miss fault */ +		case 26:	/* PCXL: Data memory access rights trap */ +		default: +			si.si_signo = SIGSEGV; +			si.si_code = SEGV_MAPERR; +		}  		si.si_errno = 0; -		si.si_code = SEGV_MAPERR;  		si.si_addr = (void __user *) address; -		force_sig_info(SIGSEGV, &si, current); +		force_sig_info(si.si_signo, &si, current);  		return;  	}  |