diff options
Diffstat (limited to 'arch/parisc/mm')
| -rw-r--r-- | arch/parisc/mm/fault.c | 101 | ||||
| -rw-r--r-- | arch/parisc/mm/init.c | 79 | 
2 files changed, 111 insertions, 69 deletions
diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index 00c0ed333a3..3ca9c1131cf 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -19,10 +19,6 @@  #include <asm/uaccess.h>  #include <asm/traps.h> -#define PRINT_USER_FAULTS /* (turn this on if you want user faults to be */ -			 /*  dumped to the console via printk)          */ - -  /* Various important other fields */  #define bit22set(x)		(x & 0x00000200)  #define bits23_25set(x)		(x & 0x000001c0) @@ -34,6 +30,8 @@  DEFINE_PER_CPU(struct exception_data, exception_data); +int show_unhandled_signals = 1; +  /*   * parisc_acctyp(unsigned int inst) --   *    Given a PA-RISC memory access instruction, determine if the @@ -142,10 +140,16 @@ 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; -		d = &__get_cpu_var(exception_data); +		d = this_cpu_ptr(&exception_data);  		d->fault_ip = regs->iaoq[0];  		d->fault_space = regs->isr;  		d->fault_addr = regs->ior; @@ -167,24 +171,55 @@ int fixup_exception(struct pt_regs *regs)  	return 0;  } +/* + * Print out info about fatal segfaults, if the show_unhandled_signals + * sysctl is set: + */ +static inline void +show_signal_msg(struct pt_regs *regs, unsigned long code, +		unsigned long address, struct task_struct *tsk, +		struct vm_area_struct *vma) +{ +	if (!unhandled_signal(tsk, SIGSEGV)) +		return; + +	if (!printk_ratelimit()) +		return; + +	pr_warn("\n"); +	pr_warn("do_page_fault() command='%s' type=%lu address=0x%08lx", +	    tsk->comm, code, address); +	print_vma_addr(KERN_CONT " in ", regs->iaoq[0]); +	if (vma) +		pr_warn(" vm_start = 0x%08lx, vm_end = 0x%08lx\n", +				vma->vm_start, vma->vm_end); + +	show_regs(regs); +} +  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: @@ -259,22 +294,42 @@ bad_area:  	if (user_mode(regs)) {  		struct siginfo si; -#ifdef PRINT_USER_FAULTS -		printk(KERN_DEBUG "\n"); -		printk(KERN_DEBUG "do_page_fault() pid=%d command='%s' type=%lu address=0x%08lx\n", -		    task_pid_nr(tsk), tsk->comm, code, address); -		if (vma) { -			printk(KERN_DEBUG "vm_start = 0x%08lx, vm_end = 0x%08lx\n", -					vma->vm_start, vma->vm_end); +		show_signal_msg(regs, code, address, tsk, vma); + +		switch (code) { +		case 15:	/* Data TLB miss fault/Data page fault */ +			/* send SIGSEGV when outside of vma */ +			if (!vma || +			    address < vma->vm_start || address > vma->vm_end) { +				si.si_signo = SIGSEGV; +				si.si_code = SEGV_MAPERR; +				break; +			} + +			/* send SIGSEGV for wrong permissions */ +			if ((vma->vm_flags & acc_type) != acc_type) { +				si.si_signo = SIGSEGV; +				si.si_code = SEGV_ACCERR; +				break; +			} + +			/* probably address is outside of mapped file */ +			/* fall through */ +		case 17:	/* NA data TLB miss / page fault */ +		case 18:	/* Unaligned access - PCXS only */ +			si.si_signo = SIGBUS; +			si.si_code = (code == 18) ? BUS_ADRALN : 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 = (code == 26) ? SEGV_ACCERR : SEGV_MAPERR; +			break;  		} -		show_regs(regs); -#endif -		/* FIXME: actually we need to get the signo and code correct */ -		si.si_signo = SIGSEGV;  		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;  	} diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index b0f96c0e631..0bef864264c 100644 --- a/arch/parisc/mm/init.c +++ b/arch/parisc/mm/init.c @@ -32,6 +32,7 @@  #include <asm/sections.h>  extern int  data_start; +extern void parisc_kernel_start(void);	/* Kernel entry point in head.S */  #if PT_NLEVELS == 3  /* NOTE: This layout exactly conforms to the hybrid L2/L3 page table layout @@ -324,8 +325,9 @@ static void __init setup_bootmem(void)  	reserve_bootmem_node(NODE_DATA(0), 0UL,  			(unsigned long)(PAGE0->mem_free +  				PDC_CONSOLE_IO_IODC_SIZE), BOOTMEM_DEFAULT); -	reserve_bootmem_node(NODE_DATA(0), __pa((unsigned long)_text), -			(unsigned long)(_end - _text), BOOTMEM_DEFAULT); +	reserve_bootmem_node(NODE_DATA(0), __pa(KERNEL_BINARY_TEXT_START), +			(unsigned long)(_end - KERNEL_BINARY_TEXT_START), +			BOOTMEM_DEFAULT);  	reserve_bootmem_node(NODE_DATA(0), (bootmap_start_pfn << PAGE_SHIFT),  			((bootmap_pfn - bootmap_start_pfn) << PAGE_SHIFT),  			BOOTMEM_DEFAULT); @@ -378,6 +380,17 @@ static void __init setup_bootmem(void)  	request_resource(&sysram_resources[0], &pdcdata_resource);  } +static int __init parisc_text_address(unsigned long vaddr) +{ +	static unsigned long head_ptr __initdata; + +	if (!head_ptr) +		head_ptr = PAGE_MASK & (unsigned long) +			dereference_function_descriptor(&parisc_kernel_start); + +	return core_kernel_text(vaddr) || vaddr == head_ptr; +} +  static void __init map_pages(unsigned long start_vaddr,  			     unsigned long start_paddr, unsigned long size,  			     pgprot_t pgprot, int force) @@ -466,7 +479,7 @@ static void __init map_pages(unsigned long start_vaddr,  				 */  				if (force)  					pte =  __mk_pte(address, pgprot); -				else if (core_kernel_text(vaddr) && +				else if (parisc_text_address(vaddr) &&  					 address != fv_addr)  					pte = __mk_pte(address, PAGE_KERNEL_EXEC);  				else @@ -632,55 +645,30 @@ EXPORT_SYMBOL(empty_zero_page);  void show_mem(unsigned int filter)  { -	int i,free = 0,total = 0,reserved = 0; -	int shared = 0, cached = 0; +	int total = 0,reserved = 0; +	pg_data_t *pgdat;  	printk(KERN_INFO "Mem-info:\n");  	show_free_areas(filter); -	if (filter & SHOW_MEM_FILTER_PAGE_COUNT) -		return; -#ifndef CONFIG_DISCONTIGMEM -	i = max_mapnr; -	while (i-- > 0) { -		total++; -		if (PageReserved(mem_map+i)) -			reserved++; -		else if (PageSwapCache(mem_map+i)) -			cached++; -		else if (!page_count(&mem_map[i])) -			free++; -		else -			shared += page_count(&mem_map[i]) - 1; -	} -#else -	for (i = 0; i < npmem_ranges; i++) { -		int j; -		for (j = node_start_pfn(i); j < node_end_pfn(i); j++) { -			struct page *p; -			unsigned long flags; - -			pgdat_resize_lock(NODE_DATA(i), &flags); -			p = nid_page_nr(i, j) - node_start_pfn(i); - -			total++; -			if (PageReserved(p)) -				reserved++; -			else if (PageSwapCache(p)) -				cached++; -			else if (!page_count(p)) -				free++; -			else -				shared += page_count(p) - 1; -			pgdat_resize_unlock(NODE_DATA(i), &flags); -        	} +	for_each_online_pgdat(pgdat) { +		unsigned long flags; +		int zoneid; + +		pgdat_resize_lock(pgdat, &flags); +		for (zoneid = 0; zoneid < MAX_NR_ZONES; zoneid++) { +			struct zone *zone = &pgdat->node_zones[zoneid]; +			if (!populated_zone(zone)) +				continue; + +			total += zone->present_pages; +			reserved = zone->present_pages - zone->managed_pages; +		} +		pgdat_resize_unlock(pgdat, &flags);  	} -#endif +  	printk(KERN_INFO "%d pages of RAM\n", total);  	printk(KERN_INFO "%d reserved pages\n", reserved); -	printk(KERN_INFO "%d pages shared\n", shared); -	printk(KERN_INFO "%d pages swap cached\n", cached); -  #ifdef CONFIG_DISCONTIGMEM  	{ @@ -740,7 +728,6 @@ static void __init pagetable_init(void)  #endif  	empty_zero_page = alloc_bootmem_pages(PAGE_SIZE); -	memset(empty_zero_page, 0, PAGE_SIZE);  }  static void __init gateway_init(void)  | 
