Commit b5a1bcbe authored by Stuart Menefy's avatar Stuart Menefy Committed by Paul Mundt
Browse files

sh: Set up correct siginfo structures for page faults.



Remove the previous saving of fault codes into the thread_struct
as they are never used, and appeared to be inherited from x86.

Signed-off-by: default avatarStuart Menefy <stuart.menefy@st.com>
Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent f0bc814c
Loading
Loading
Loading
Loading
+1 −6
Original line number Diff line number Diff line
@@ -282,11 +282,8 @@ ieee_fpe_handler (struct pt_regs *regs)
			grab_fpu(regs);
			restore_fpu(tsk);
			set_tsk_thread_flag(tsk, TIF_USEDFPU);
		} else {
			tsk->thread.trap_no = 11;
			tsk->thread.error_code = 0;
		} else
			force_sig(SIGFPE, tsk);
		}

		regs->pc = nextpc;
		return 1;
@@ -307,8 +304,6 @@ do_fpu_error(unsigned long r4, unsigned long r5, unsigned long r6,

	regs->pc += 2;
	save_fpu(tsk, regs);
	tsk->thread.trap_no = 11;
	tsk->thread.error_code = 0;
	force_sig(SIGFPE, tsk);
}

+40 −34
Original line number Diff line number Diff line
@@ -323,7 +323,8 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs)
			return -EFAULT;

		/* kernel */
		die("delay-slot-insn faulting in handle_unaligned_delayslot", regs, 0);
		die("delay-slot-insn faulting in handle_unaligned_delayslot",
		    regs, 0);
	}

	return handle_unaligned_ins(instruction,regs);
@@ -364,7 +365,8 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
	if (user_mode(regs) && handle_unaligned_notify_count>0) {
		handle_unaligned_notify_count--;

		printk("Fixing up unaligned userspace access in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
		printk(KERN_NOTICE "Fixing up unaligned userspace access "
		       "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
		       current->comm,current->pid,(u16*)regs->pc,instruction);
	}

@@ -499,7 +501,15 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
#endif

/*
 * Handle various address error exceptions
 * Handle various address error exceptions:
 *  - instruction address error:
 *       misaligned PC
 *       PC >= 0x80000000 in user mode
 *  - data address error (read and write)
 *       misaligned data access
 *       access to >= 0x80000000 is user mode
 * Unfortuntaly we can't distinguish between instruction address error
 * and data address errors caused by read acceses.
 */
asmlinkage void do_address_error(struct pt_regs *regs,
				 unsigned long writeaccess,
@@ -507,6 +517,7 @@ asmlinkage void do_address_error(struct pt_regs *regs,
{
	unsigned long error_code = 0;
	mm_segment_t oldfs;
	siginfo_t info;
#ifndef CONFIG_CPU_SH2A
	u16 instruction;
	int tmp;
@@ -520,22 +531,15 @@ asmlinkage void do_address_error(struct pt_regs *regs,
	oldfs = get_fs();

	if (user_mode(regs)) {
		int si_code = BUS_ADRERR;

		local_irq_enable();
		current->thread.error_code = error_code;
#ifdef CONFIG_CPU_SH2
		/*
		 * On the SH-2, we only have a single vector for address
		 * errors, there's no differentiating between a load error
		 * and a store error.
		 */
		current->thread.trap_no = 9;
#else
		current->thread.trap_no = (writeaccess) ? 8 : 7;
#endif

		/* bad PC is not something we can fix */
		if (regs->pc & 1)
		if (regs->pc & 1) {
			si_code = BUS_ADRALN;
			goto uspace_segv;
		}

#ifndef CONFIG_CPU_SH2A
		set_fs(USER_DS);
@@ -555,8 +559,15 @@ asmlinkage void do_address_error(struct pt_regs *regs,
#endif

uspace_segv:
		printk(KERN_NOTICE "Killing process \"%s\" due to unaligned access\n", current->comm);
		force_sig(SIGSEGV, current);
		printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned "
		       "access (PC %lx PR %lx)\n", current->comm, regs->pc,
		       regs->pr);

		info.si_signo = SIGBUS;
		info.si_errno = 0;
		info.si_code = si_code;
		info.si_addr = (void *) address;
		force_sig_info(SIGBUS, &info, current);
	} else {
		if (regs->pc & 1)
			die("unaligned program counter", regs, error_code);
@@ -574,7 +585,9 @@ asmlinkage void do_address_error(struct pt_regs *regs,
		handle_unaligned_access(instruction, regs);
		set_fs(oldfs);
#else
		printk(KERN_NOTICE "Killing process \"%s\" due to unaligned access\n", current->comm);
		printk(KERN_NOTICE "Killing process \"%s\" due to unaligned "
		       "access\n", current->comm);

		force_sig(SIGSEGV, current);
#endif
	}
@@ -617,9 +630,6 @@ asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
	struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
	siginfo_t info;

	current->thread.trap_no = r4;
	current->thread.error_code = 0;

	switch (r4) {
	case TRAP_DIVZERO_ERROR:
		info.si_code = FPE_INTDIV;
@@ -672,8 +682,6 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
	lookup_exception_vector(error_code);

	local_irq_enable();
	tsk->thread.error_code = error_code;
	tsk->thread.trap_no = TRAP_RESERVED_INST;
	CHK_REMOTE_DEBUG(regs);
	force_sig(SIGILL, tsk);
	die_if_no_fixup("reserved instruction", regs, error_code);
@@ -745,8 +753,6 @@ asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
	lookup_exception_vector(error_code);

	local_irq_enable();
	tsk->thread.error_code = error_code;
	tsk->thread.trap_no = TRAP_RESERVED_INST;
	CHK_REMOTE_DEBUG(regs);
	force_sig(SIGILL, tsk);
	die_if_no_fixup("illegal slot instruction", regs, error_code);
+17 −9
Original line number Diff line number Diff line
@@ -26,13 +26,16 @@ extern void die(const char *,struct pt_regs *,long);
 * and the problem, and then passes it off to one of the appropriate
 * routines.
 */
asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
					unsigned long writeaccess,
					unsigned long address)
{
	struct task_struct *tsk;
	struct mm_struct *mm;
	struct vm_area_struct * vma;
	unsigned long page;
	int si_code;
	siginfo_t info;

#ifdef CONFIG_SH_KGDB
	if (kgdb_nofault && kgdb_bus_err_hook)
@@ -41,6 +44,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,

	tsk = current;
	mm = tsk->mm;
	si_code = SEGV_MAPERR;

	/*
	 * If we're in an interrupt or have no user
@@ -65,6 +69,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
 * we can handle it..
 */
good_area:
	si_code = SEGV_ACCERR;
	if (writeaccess) {
		if (!(vma->vm_flags & VM_WRITE))
			goto bad_area;
@@ -105,9 +110,11 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
	up_read(&mm->mmap_sem);

	if (user_mode(regs)) {
		tsk->thread.address = address;
		tsk->thread.error_code = writeaccess;
		force_sig(SIGSEGV, tsk);
		info.si_signo = SIGSEGV;
		info.si_errno = 0;
		info.si_code = si_code;
		info.si_addr = (void *) address;
		force_sig_info(SIGSEGV, &info, tsk);
		return;
	}

@@ -166,10 +173,11 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
	 * Send a sigbus, regardless of whether we were in kernel
	 * or user mode.
	 */
	tsk->thread.address = address;
	tsk->thread.error_code = writeaccess;
	tsk->thread.trap_no = 14;
	force_sig(SIGBUS, tsk);
	info.si_signo = SIGBUS;
	info.si_errno = 0;
	info.si_code = BUS_ADRERR;
	info.si_addr = (void *)address;
	force_sig_info(SIGBUS, &info, tsk);

	/* Kernel mode? Handle exceptions or die */
	if (!user_mode(regs))
+3 −9
Original line number Diff line number Diff line
@@ -136,12 +136,11 @@ union sh_fpu_union {
};

struct thread_struct {
	/* Saved registers when thread is descheduled */
	unsigned long sp;
	unsigned long pc;

	unsigned long trap_no, error_code;
	unsigned long address;
	/* Hardware debugging registers may come here */
	/* Hardware debugging registers */
	unsigned long ubc_pc;

	/* floating point info */
@@ -156,12 +155,7 @@ typedef struct {
extern int ubc_usercnt;

#define INIT_THREAD  {						\
	sizeof(init_stack) + (long) &init_stack, /* sp */	\
	0,					 /* pc */	\
	0, 0,							\
	0,							\
	0,							\
	{{{0,}},}				/* fpu state */	\
	.sp = sizeof(init_stack) + (long) &init_stack,		\
}

/*