diff options
Diffstat (limited to 'arch/sparc/mm/fault_32.c')
| -rw-r--r-- | arch/sparc/mm/fault_32.c | 207 | 
1 files changed, 45 insertions, 162 deletions
diff --git a/arch/sparc/mm/fault_32.c b/arch/sparc/mm/fault_32.c index df3155a1799..f46cf6be337 100644 --- a/arch/sparc/mm/fault_32.c +++ b/arch/sparc/mm/fault_32.c @@ -24,29 +24,19 @@  #include <asm/page.h>  #include <asm/pgtable.h> -#include <asm/memreg.h>  #include <asm/openprom.h>  #include <asm/oplib.h>  #include <asm/smp.h>  #include <asm/traps.h>  #include <asm/uaccess.h> -extern int prom_node_root; -  int show_unhandled_signals = 1;  /* At boot time we determine these two values necessary for setting   * up the segment maps and page table entries (pte's).   */ -int num_segmaps, num_contexts; -int invalid_segment; - -/* various Virtual Address Cache parameters we find at boot time... */ - -int vac_size, vac_linesize, vac_do_hw_vac_flushes; -int vac_entries_per_context, vac_entries_per_segment; -int vac_entries_per_page; +int num_contexts;  /* Return how much physical memory we have.  */  unsigned long probe_memory(void) @@ -60,55 +50,36 @@ unsigned long probe_memory(void)  	return total;  } -extern void sun4c_complete_all_stores(void); - -/* Whee, a level 15 NMI interrupt memory error.  Let's have fun... */ -asmlinkage void sparc_lvl15_nmi(struct pt_regs *regs, unsigned long serr, -				unsigned long svaddr, unsigned long aerr, -				unsigned long avaddr) -{ -	sun4c_complete_all_stores(); -	printk("FAULT: NMI received\n"); -	printk("SREGS: Synchronous Error %08lx\n", serr); -	printk("       Synchronous Vaddr %08lx\n", svaddr); -	printk("      Asynchronous Error %08lx\n", aerr); -	printk("      Asynchronous Vaddr %08lx\n", avaddr); -	if (sun4c_memerr_reg) -		printk("     Memory Parity Error %08lx\n", *sun4c_memerr_reg); -	printk("REGISTER DUMP:\n"); -	show_regs(regs); -	prom_halt(); -} -  static void unhandled_fault(unsigned long, struct task_struct *,  		struct pt_regs *) __attribute__ ((noreturn)); -static void unhandled_fault(unsigned long address, struct task_struct *tsk, -                     struct pt_regs *regs) +static void __noreturn unhandled_fault(unsigned long address, +				       struct task_struct *tsk, +				       struct pt_regs *regs)  { -	if((unsigned long) address < PAGE_SIZE) { +	if ((unsigned long) address < PAGE_SIZE) {  		printk(KERN_ALERT  		    "Unable to handle kernel NULL pointer dereference\n");  	} else { -		printk(KERN_ALERT "Unable to handle kernel paging request " -		       "at virtual address %08lx\n", address); +		printk(KERN_ALERT "Unable to handle kernel paging request at virtual address %08lx\n", +		       address);  	}  	printk(KERN_ALERT "tsk->{mm,active_mm}->context = %08lx\n",  		(tsk->mm ? tsk->mm->context : tsk->active_mm->context));  	printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %08lx\n",  		(tsk->mm ? (unsigned long) tsk->mm->pgd : -		 	(unsigned long) tsk->active_mm->pgd)); +			(unsigned long) tsk->active_mm->pgd));  	die_if_kernel("Oops", regs);  } -asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,  +asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,  			    unsigned long address)  {  	struct pt_regs regs;  	unsigned long g2;  	unsigned int insn;  	int i; -	 +  	i = search_extables_range(ret_pc, &g2);  	switch (i) {  	case 3: @@ -128,14 +99,14 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,  		/* for _from_ macros */  		insn = *((unsigned int *) pc);  		if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15) -			return 2;  -		break;  +			return 2; +		break;  	default:  		break;  	} -	memset(®s, 0, sizeof (regs)); +	memset(®s, 0, sizeof(regs));  	regs.pc = pc;  	regs.npc = pc + 4;  	__asm__ __volatile__( @@ -198,11 +169,10 @@ static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault)  	if (text_fault)  		return regs->pc; -	if (regs->psr & PSR_PS) { +	if (regs->psr & PSR_PS)  		insn = *(unsigned int *) regs->pc; -	} else { +	else  		__get_user(insn, (unsigned int *) regs->pc); -	}  	return safe_compute_effective_address(regs, insn);  } @@ -228,7 +198,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,  	unsigned int flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |  			      (write ? FAULT_FLAG_WRITE : 0)); -	if(text_fault) +	if (text_fault)  		address = regs->pc;  	/* @@ -241,36 +211,32 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,  	 * nothing more.  	 */  	code = SEGV_MAPERR; -	if (!ARCH_SUN4C && address >= TASK_SIZE) +	if (address >= TASK_SIZE)  		goto vmalloc_fault;  	/*  	 * If we're in an interrupt or have no user  	 * context, we must not take the fault..  	 */ -        if (in_atomic() || !mm) -                goto no_context; +	if (in_atomic() || !mm) +		goto no_context;  	perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);  retry:  	down_read(&mm->mmap_sem); -	/* -	 * The kernel referencing a bad kernel pointer can lock up -	 * a sun4c machine completely, so we must attempt recovery. -	 */ -	if(!from_user && address >= PAGE_OFFSET) +	if (!from_user && address >= PAGE_OFFSET)  		goto bad_area;  	vma = find_vma(mm, address); -	if(!vma) +	if (!vma)  		goto bad_area; -	if(vma->vm_start <= address) +	if (vma->vm_start <= address)  		goto good_area; -	if(!(vma->vm_flags & VM_GROWSDOWN)) +	if (!(vma->vm_flags & VM_GROWSDOWN))  		goto bad_area; -	if(expand_stack(vma, address)) +	if (expand_stack(vma, address))  		goto bad_area;  	/*  	 * Ok, we have a good vm_area for this memory access, so @@ -278,12 +244,12 @@ retry:  	 */  good_area:  	code = SEGV_ACCERR; -	if(write) { -		if(!(vma->vm_flags & VM_WRITE)) +	if (write) { +		if (!(vma->vm_flags & VM_WRITE))  			goto bad_area;  	} else {  		/* Allow reads even for write-only mappings */ -		if(!(vma->vm_flags & (VM_READ | VM_EXEC))) +		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))  			goto bad_area;  	} @@ -349,14 +315,16 @@ no_context:  	g2 = regs->u_regs[UREG_G2];  	if (!from_user) {  		fixup = search_extables_range(regs->pc, &g2); -		if (fixup > 10) { /* Values below are reserved for other things */ +		/* Values below 10 are reserved for other things */ +		if (fixup > 10) {  			extern const unsigned __memset_start[];  			extern const unsigned __memset_end[];  			extern const unsigned __csum_partial_copy_start[];  			extern const unsigned __csum_partial_copy_end[];  #ifdef DEBUG_EXCEPTIONS -			printk("Exception: PC<%08lx> faddr<%08lx>\n", regs->pc, address); +			printk("Exception: PC<%08lx> faddr<%08lx>\n", +			       regs->pc, address);  			printk("EX_TABLE: insn<%08lx> fixup<%08x> g2<%08lx>\n",  				regs->pc, fixup, g2);  #endif @@ -364,7 +332,7 @@ no_context:  			     regs->pc < (unsigned long)__memset_end) ||  			    (regs->pc >= (unsigned long)__csum_partial_copy_start &&  			     regs->pc < (unsigned long)__csum_partial_copy_end)) { -			        regs->u_regs[UREG_I4] = address; +				regs->u_regs[UREG_I4] = address;  				regs->u_regs[UREG_I5] = regs->pc;  			}  			regs->u_regs[UREG_G2] = g2; @@ -373,8 +341,8 @@ no_context:  			return;  		}  	} -	 -	unhandled_fault (address, tsk, regs); + +	unhandled_fault(address, tsk, regs);  	do_exit(SIGKILL);  /* @@ -420,97 +388,12 @@ vmalloc_fault:  		if (pmd_present(*pmd) || !pmd_present(*pmd_k))  			goto bad_area_nosemaphore; +  		*pmd = *pmd_k;  		return;  	}  } -asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write, -			       unsigned long address) -{ -	extern void sun4c_update_mmu_cache(struct vm_area_struct *, -					   unsigned long,pte_t *); -	extern pte_t *sun4c_pte_offset_kernel(pmd_t *,unsigned long); -	struct task_struct *tsk = current; -	struct mm_struct *mm = tsk->mm; -	pgd_t *pgdp; -	pte_t *ptep; - -	if (text_fault) { -		address = regs->pc; -	} else if (!write && -		   !(regs->psr & PSR_PS)) { -		unsigned int insn, __user *ip; - -		ip = (unsigned int __user *)regs->pc; -		if (!get_user(insn, ip)) { -			if ((insn & 0xc1680000) == 0xc0680000) -				write = 1; -		} -	} - -	if (!mm) { -		/* We are oopsing. */ -		do_sparc_fault(regs, text_fault, write, address); -		BUG();	/* P3 Oops already, you bitch */ -	} - -	pgdp = pgd_offset(mm, address); -	ptep = sun4c_pte_offset_kernel((pmd_t *) pgdp, address); - -	if (pgd_val(*pgdp)) { -	    if (write) { -		if ((pte_val(*ptep) & (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT)) -				   == (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT)) { -			unsigned long flags; - -			*ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED | -				      _SUN4C_PAGE_MODIFIED | -				      _SUN4C_PAGE_VALID | -				      _SUN4C_PAGE_DIRTY); - -			local_irq_save(flags); -			if (sun4c_get_segmap(address) != invalid_segment) { -				sun4c_put_pte(address, pte_val(*ptep)); -				local_irq_restore(flags); -				return; -			} -			local_irq_restore(flags); -		} -	    } else { -		if ((pte_val(*ptep) & (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT)) -				   == (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT)) { -			unsigned long flags; - -			*ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED | -				      _SUN4C_PAGE_VALID); - -			local_irq_save(flags); -			if (sun4c_get_segmap(address) != invalid_segment) { -				sun4c_put_pte(address, pte_val(*ptep)); -				local_irq_restore(flags); -				return; -			} -			local_irq_restore(flags); -		} -	    } -	} - -	/* This conditional is 'interesting'. */ -	if (pgd_val(*pgdp) && !(write && !(pte_val(*ptep) & _SUN4C_PAGE_WRITE)) -	    && (pte_val(*ptep) & _SUN4C_PAGE_VALID)) -		/* Note: It is safe to not grab the MMAP semaphore here because -		 *       we know that update_mmu_cache() will not sleep for -		 *       any reason (at least not in the current implementation) -		 *       and therefore there is no danger of another thread getting -		 *       on the CPU and doing a shrink_mmap() on this vma. -		 */ -		sun4c_update_mmu_cache (find_vma(current->mm, address), address, -					ptep); -	else -		do_sparc_fault(regs, text_fault, write, address); -} -  /* This always deals with user addresses. */  static void force_user_fault(unsigned long address, int write)  { @@ -523,21 +406,21 @@ static void force_user_fault(unsigned long address, int write)  	down_read(&mm->mmap_sem);  	vma = find_vma(mm, address); -	if(!vma) +	if (!vma)  		goto bad_area; -	if(vma->vm_start <= address) +	if (vma->vm_start <= address)  		goto good_area; -	if(!(vma->vm_flags & VM_GROWSDOWN)) +	if (!(vma->vm_flags & VM_GROWSDOWN))  		goto bad_area; -	if(expand_stack(vma, address)) +	if (expand_stack(vma, address))  		goto bad_area;  good_area:  	code = SEGV_ACCERR; -	if(write) { -		if(!(vma->vm_flags & VM_WRITE)) +	if (write) { +		if (!(vma->vm_flags & VM_WRITE))  			goto bad_area;  	} else { -		if(!(vma->vm_flags & (VM_READ | VM_EXEC))) +		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))  			goto bad_area;  	}  	switch (handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0)) { @@ -568,7 +451,7 @@ void window_overflow_fault(void)  	unsigned long sp;  	sp = current_thread_info()->rwbuf_stkptrs[0]; -	if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) +	if (((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))  		force_user_fault(sp + 0x38, 1);  	force_user_fault(sp, 1); @@ -577,7 +460,7 @@ void window_overflow_fault(void)  void window_underflow_fault(unsigned long sp)  { -	if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) +	if (((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))  		force_user_fault(sp + 0x38, 0);  	force_user_fault(sp, 0); @@ -589,7 +472,7 @@ void window_ret_fault(struct pt_regs *regs)  	unsigned long sp;  	sp = regs->u_regs[UREG_FP]; -	if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) +	if (((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))  		force_user_fault(sp + 0x38, 0);  	force_user_fault(sp, 0);  |