diff options
Diffstat (limited to 'arch/powerpc/mm/fault.c')
| -rw-r--r-- | arch/powerpc/mm/fault.c | 55 | 
1 files changed, 30 insertions, 25 deletions
| diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index d51cf5f4e45e..1697e903bbf2 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -103,8 +103,7 @@ static bool store_updates_sp(unsigned int inst)   */  static int -__bad_area_nosemaphore(struct pt_regs *regs, unsigned long address, int si_code, -		int pkey) +__bad_area_nosemaphore(struct pt_regs *regs, unsigned long address, int si_code)  {  	/*  	 * If we are in kernel mode, bail out with a SEGV, this will @@ -114,18 +113,17 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long address, int si_code,  	if (!user_mode(regs))  		return SIGSEGV; -	_exception_pkey(SIGSEGV, regs, si_code, address, pkey); +	_exception(SIGSEGV, regs, si_code, address);  	return 0;  }  static noinline int bad_area_nosemaphore(struct pt_regs *regs, unsigned long address)  { -	return __bad_area_nosemaphore(regs, address, SEGV_MAPERR, 0); +	return __bad_area_nosemaphore(regs, address, SEGV_MAPERR);  } -static int __bad_area(struct pt_regs *regs, unsigned long address, int si_code, -			int pkey) +static int __bad_area(struct pt_regs *regs, unsigned long address, int si_code)  {  	struct mm_struct *mm = current->mm; @@ -135,54 +133,61 @@ static int __bad_area(struct pt_regs *regs, unsigned long address, int si_code,  	 */  	up_read(&mm->mmap_sem); -	return __bad_area_nosemaphore(regs, address, si_code, pkey); +	return __bad_area_nosemaphore(regs, address, si_code);  }  static noinline int bad_area(struct pt_regs *regs, unsigned long address)  { -	return __bad_area(regs, address, SEGV_MAPERR, 0); +	return __bad_area(regs, address, SEGV_MAPERR);  }  static int bad_key_fault_exception(struct pt_regs *regs, unsigned long address,  				    int pkey)  { -	return __bad_area_nosemaphore(regs, address, SEGV_PKUERR, pkey); +	/* +	 * If we are in kernel mode, bail out with a SEGV, this will +	 * be caught by the assembly which will restore the non-volatile +	 * registers before calling bad_page_fault() +	 */ +	if (!user_mode(regs)) +		return SIGSEGV; + +	_exception_pkey(regs, address, pkey); + +	return 0;  }  static noinline int bad_access(struct pt_regs *regs, unsigned long address)  { -	return __bad_area(regs, address, SEGV_ACCERR, 0); +	return __bad_area(regs, address, SEGV_ACCERR);  }  static int do_sigbus(struct pt_regs *regs, unsigned long address,  		     vm_fault_t fault)  { -	siginfo_t info; -	unsigned int lsb = 0; -  	if (!user_mode(regs))  		return SIGBUS;  	current->thread.trap_nr = BUS_ADRERR; -	clear_siginfo(&info); -	info.si_signo = SIGBUS; -	info.si_errno = 0; -	info.si_code = BUS_ADRERR; -	info.si_addr = (void __user *)address;  #ifdef CONFIG_MEMORY_FAILURE  	if (fault & (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) { +		unsigned int lsb = 0; /* shutup gcc */ +  		pr_err("MCE: Killing %s:%d due to hardware memory corruption fault at %lx\n",  			current->comm, current->pid, address); -		info.si_code = BUS_MCEERR_AR; + +		if (fault & VM_FAULT_HWPOISON_LARGE) +			lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault)); +		if (fault & VM_FAULT_HWPOISON) +			lsb = PAGE_SHIFT; + +		force_sig_mceerr(BUS_MCEERR_AR, (void __user *)address, lsb, +				 current); +		return 0;  	} -	if (fault & VM_FAULT_HWPOISON_LARGE) -		lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault)); -	if (fault & VM_FAULT_HWPOISON) -		lsb = PAGE_SHIFT;  #endif -	info.si_addr_lsb = lsb; -	force_sig_info(SIGBUS, &info, current); +	force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address, current);  	return 0;  } |