300 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			300 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *  arch/microblaze/mm/fault.c
 | |
|  *
 | |
|  *    Copyright (C) 2007 Xilinx, Inc.  All rights reserved.
 | |
|  *
 | |
|  *  Derived from "arch/ppc/mm/fault.c"
 | |
|  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
 | |
|  *
 | |
|  *  Derived from "arch/i386/mm/fault.c"
 | |
|  *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
 | |
|  *
 | |
|  *  Modified by Cort Dougan and Paul Mackerras.
 | |
|  *
 | |
|  * This file is subject to the terms and conditions of the GNU General
 | |
|  * Public License.  See the file COPYING in the main directory of this
 | |
|  * archive for more details.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include <linux/module.h>
 | |
| #include <linux/signal.h>
 | |
| #include <linux/sched.h>
 | |
| #include <linux/kernel.h>
 | |
| #include <linux/errno.h>
 | |
| #include <linux/string.h>
 | |
| #include <linux/types.h>
 | |
| #include <linux/ptrace.h>
 | |
| #include <linux/mman.h>
 | |
| #include <linux/mm.h>
 | |
| #include <linux/interrupt.h>
 | |
| 
 | |
| #include <asm/page.h>
 | |
| #include <asm/pgtable.h>
 | |
| #include <asm/mmu.h>
 | |
| #include <asm/mmu_context.h>
 | |
| #include <asm/system.h>
 | |
| #include <linux/uaccess.h>
 | |
| #include <asm/exceptions.h>
 | |
| 
 | |
| #if defined(CONFIG_KGDB)
 | |
| int debugger_kernel_faults = 1;
 | |
| #endif
 | |
| 
 | |
| static unsigned long pte_misses;	/* updated by do_page_fault() */
 | |
| static unsigned long pte_errors;	/* updated by do_page_fault() */
 | |
| 
 | |
| /*
 | |
|  * Check whether the instruction at regs->pc is a store using
 | |
|  * an update addressing form which will update r1.
 | |
|  */
 | |
| static int store_updates_sp(struct pt_regs *regs)
 | |
| {
 | |
| 	unsigned int inst;
 | |
| 
 | |
| 	if (get_user(inst, (unsigned int *)regs->pc))
 | |
| 		return 0;
 | |
| 	/* check for 1 in the rD field */
 | |
| 	if (((inst >> 21) & 0x1f) != 1)
 | |
| 		return 0;
 | |
| 	/* check for store opcodes */
 | |
| 	if ((inst & 0xd0000000) == 0xd0000000)
 | |
| 		return 1;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
|  * bad_page_fault is called when we have a bad access from the kernel.
 | |
|  * It is called from do_page_fault above and from some of the procedures
 | |
|  * in traps.c.
 | |
|  */
 | |
| void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
 | |
| {
 | |
| 	const struct exception_table_entry *fixup;
 | |
| /* MS: no context */
 | |
| 	/* Are we prepared to handle this fault?  */
 | |
| 	fixup = search_exception_tables(regs->pc);
 | |
| 	if (fixup) {
 | |
| 		regs->pc = fixup->fixup;
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	/* kernel has accessed a bad area */
 | |
| #if defined(CONFIG_KGDB)
 | |
| 	if (debugger_kernel_faults)
 | |
| 		debugger(regs);
 | |
| #endif
 | |
| 	die("kernel access of bad area", regs, sig);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * The error_code parameter is ESR for a data fault,
 | |
|  * 0 for an instruction fault.
 | |
|  */
 | |
| void do_page_fault(struct pt_regs *regs, unsigned long address,
 | |
| 		   unsigned long error_code)
 | |
| {
 | |
| 	struct vm_area_struct *vma;
 | |
| 	struct mm_struct *mm = current->mm;
 | |
| 	siginfo_t info;
 | |
| 	int code = SEGV_MAPERR;
 | |
| 	int is_write = error_code & ESR_S;
 | |
| 	int fault;
 | |
| 
 | |
| 	regs->ear = address;
 | |
| 	regs->esr = error_code;
 | |
| 
 | |
| 	/* On a kernel SLB miss we can only check for a valid exception entry */
 | |
| 	if (kernel_mode(regs) && (address >= TASK_SIZE)) {
 | |
| 		printk(KERN_WARNING "kernel task_size exceed");
 | |
| 		_exception(SIGSEGV, regs, code, address);
 | |
| 	}
 | |
| 
 | |
| 	/* for instr TLB miss and instr storage exception ESR_S is undefined */
 | |
| 	if ((error_code & 0x13) == 0x13 || (error_code & 0x11) == 0x11)
 | |
| 		is_write = 0;
 | |
| 
 | |
| #if defined(CONFIG_KGDB)
 | |
| 	if (debugger_fault_handler && regs->trap == 0x300) {
 | |
| 		debugger_fault_handler(regs);
 | |
| 		return;
 | |
| 	}
 | |
| #endif /* CONFIG_KGDB */
 | |
| 
 | |
| 	if (in_atomic() || !mm) {
 | |
| 		if (kernel_mode(regs))
 | |
| 			goto bad_area_nosemaphore;
 | |
| 
 | |
| 		/* in_atomic() in user mode is really bad,
 | |
| 		   as is current->mm == NULL. */
 | |
| 		printk(KERN_EMERG "Page fault in user mode with "
 | |
| 		       "in_atomic(), mm = %p\n", mm);
 | |
| 		printk(KERN_EMERG "r15 = %lx  MSR = %lx\n",
 | |
| 		       regs->r15, regs->msr);
 | |
| 		die("Weird page fault", regs, SIGSEGV);
 | |
| 	}
 | |
| 
 | |
| 	/* When running in the kernel we expect faults to occur only to
 | |
| 	 * addresses in user space.  All other faults represent errors in the
 | |
| 	 * kernel and should generate an OOPS.  Unfortunately, in the case of an
 | |
| 	 * erroneous fault occurring in a code path which already holds mmap_sem
 | |
| 	 * we will deadlock attempting to validate the fault against the
 | |
| 	 * address space.  Luckily the kernel only validly references user
 | |
| 	 * space from well defined areas of code, which are listed in the
 | |
| 	 * exceptions table.
 | |
| 	 *
 | |
| 	 * As the vast majority of faults will be valid we will only perform
 | |
| 	 * the source reference check when there is a possibility of a deadlock.
 | |
| 	 * Attempt to lock the address space, if we cannot we then validate the
 | |
| 	 * source.  If this is invalid we can skip the address space check,
 | |
| 	 * thus avoiding the deadlock.
 | |
| 	 */
 | |
| 	if (!down_read_trylock(&mm->mmap_sem)) {
 | |
| 		if (kernel_mode(regs) && !search_exception_tables(regs->pc))
 | |
| 			goto bad_area_nosemaphore;
 | |
| 
 | |
| 		down_read(&mm->mmap_sem);
 | |
| 	}
 | |
| 
 | |
| 	vma = find_vma(mm, address);
 | |
| 	if (!vma)
 | |
| 		goto bad_area;
 | |
| 
 | |
| 	if (vma->vm_start <= address)
 | |
| 		goto good_area;
 | |
| 
 | |
| 	if (!(vma->vm_flags & VM_GROWSDOWN))
 | |
| 		goto bad_area;
 | |
| 
 | |
| 	if (!is_write)
 | |
| 		goto bad_area;
 | |
| 
 | |
| 	/*
 | |
| 	 * N.B. The ABI allows programs to access up to
 | |
| 	 * a few hundred bytes below the stack pointer (TBD).
 | |
| 	 * The kernel signal delivery code writes up to about 1.5kB
 | |
| 	 * below the stack pointer (r1) before decrementing it.
 | |
| 	 * The exec code can write slightly over 640kB to the stack
 | |
| 	 * before setting the user r1.  Thus we allow the stack to
 | |
| 	 * expand to 1MB without further checks.
 | |
| 	 */
 | |
| 	if (address + 0x100000 < vma->vm_end) {
 | |
| 
 | |
| 		/* get user regs even if this fault is in kernel mode */
 | |
| 		struct pt_regs *uregs = current->thread.regs;
 | |
| 		if (uregs == NULL)
 | |
| 			goto bad_area;
 | |
| 
 | |
| 		/*
 | |
| 		 * A user-mode access to an address a long way below
 | |
| 		 * the stack pointer is only valid if the instruction
 | |
| 		 * is one which would update the stack pointer to the
 | |
| 		 * address accessed if the instruction completed,
 | |
| 		 * i.e. either stwu rs,n(r1) or stwux rs,r1,rb
 | |
| 		 * (or the byte, halfword, float or double forms).
 | |
| 		 *
 | |
| 		 * If we don't check this then any write to the area
 | |
| 		 * between the last mapped region and the stack will
 | |
| 		 * expand the stack rather than segfaulting.
 | |
| 		 */
 | |
| 		if (address + 2048 < uregs->r1
 | |
| 			&& (kernel_mode(regs) || !store_updates_sp(regs)))
 | |
| 				goto bad_area;
 | |
| 	}
 | |
| 	if (expand_stack(vma, address))
 | |
| 		goto bad_area;
 | |
| 
 | |
| good_area:
 | |
| 	code = SEGV_ACCERR;
 | |
| 
 | |
| 	/* a write */
 | |
| 	if (is_write) {
 | |
| 		if (!(vma->vm_flags & VM_WRITE))
 | |
| 			goto bad_area;
 | |
| 	/* a read */
 | |
| 	} else {
 | |
| 		/* protection fault */
 | |
| 		if (error_code & 0x08000000)
 | |
| 			goto bad_area;
 | |
| 		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
 | |
| 			goto bad_area;
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * If for any reason at all we couldn't handle the fault,
 | |
| 	 * make sure we exit gracefully rather than endlessly redo
 | |
| 	 * the fault.
 | |
| 	 */
 | |
| survive:
 | |
| 	fault = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0);
 | |
| 	if (unlikely(fault & VM_FAULT_ERROR)) {
 | |
| 		if (fault & VM_FAULT_OOM)
 | |
| 			goto out_of_memory;
 | |
| 		else if (fault & VM_FAULT_SIGBUS)
 | |
| 			goto do_sigbus;
 | |
| 		BUG();
 | |
| 	}
 | |
| 	if (fault & VM_FAULT_MAJOR)
 | |
| 		current->maj_flt++;
 | |
| 	else
 | |
| 		current->min_flt++;
 | |
| 	up_read(&mm->mmap_sem);
 | |
| 	/*
 | |
| 	 * keep track of tlb+htab misses that are good addrs but
 | |
| 	 * just need pte's created via handle_mm_fault()
 | |
| 	 * -- Cort
 | |
| 	 */
 | |
| 	pte_misses++;
 | |
| 	return;
 | |
| 
 | |
| bad_area:
 | |
| 	up_read(&mm->mmap_sem);
 | |
| 
 | |
| bad_area_nosemaphore:
 | |
| 	pte_errors++;
 | |
| 
 | |
| 	/* User mode accesses cause a SIGSEGV */
 | |
| 	if (user_mode(regs)) {
 | |
| 		_exception(SIGSEGV, regs, code, address);
 | |
| /*		info.si_signo = SIGSEGV;
 | |
| 		info.si_errno = 0;
 | |
| 		info.si_code = code;
 | |
| 		info.si_addr = (void *) address;
 | |
| 		force_sig_info(SIGSEGV, &info, current);*/
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	bad_page_fault(regs, address, SIGSEGV);
 | |
| 	return;
 | |
| 
 | |
| /*
 | |
|  * We ran out of memory, or some other thing happened to us that made
 | |
|  * us unable to handle the page fault gracefully.
 | |
|  */
 | |
| out_of_memory:
 | |
| 	if (current->pid == 1) {
 | |
| 		yield();
 | |
| 		down_read(&mm->mmap_sem);
 | |
| 		goto survive;
 | |
| 	}
 | |
| 	up_read(&mm->mmap_sem);
 | |
| 	printk(KERN_WARNING "VM: killing process %s\n", current->comm);
 | |
| 	if (user_mode(regs))
 | |
| 		do_exit(SIGKILL);
 | |
| 	bad_page_fault(regs, address, SIGKILL);
 | |
| 	return;
 | |
| 
 | |
| do_sigbus:
 | |
| 	up_read(&mm->mmap_sem);
 | |
| 	if (user_mode(regs)) {
 | |
| 		info.si_signo = SIGBUS;
 | |
| 		info.si_errno = 0;
 | |
| 		info.si_code = BUS_ADRERR;
 | |
| 		info.si_addr = (void __user *)address;
 | |
| 		force_sig_info(SIGBUS, &info, current);
 | |
| 		return;
 | |
| 	}
 | |
| 	bad_page_fault(regs, address, SIGBUS);
 | |
| }
 |