Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 623b0355 authored by Haavard Skinnemoen's avatar Haavard Skinnemoen
Browse files

[AVR32] Clean up exception handling code



  * Use generic BUG() handling
  * Remove some useless debug statements
  * Use a common function _exception() to send signals or oops when
    an exception can't be handled. This makes sure init doesn't
    enter an infinite exception loop as well. Borrowed from powerpc.
  * Add some basic exception tracing support to the page fault code.
  * Rework dump_stack(), show_regs() and friends and move everything
    into process.c
  * Print information about configuration options and chip type when
    oopsing

Signed-off-by: default avatarHaavard Skinnemoen <hskinnemoen@atmel.com>
parent 3b328c98
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -68,6 +68,11 @@ config GENERIC_CALIBRATE_DELAY
	bool
	default y

config GENERIC_BUG
	bool
	default y
	depends on BUG

source "init/Kconfig"

menu "System Type and features"
+6 −5
Original line number Diff line number Diff line
@@ -12,10 +12,11 @@
 * published by the Free Software Foundation.
 */

#include <linux/moduleloader.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/bug.h>
#include <linux/elf.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleloader.h>
#include <linux/vmalloc.h>

void *module_alloc(unsigned long size)
@@ -315,10 +316,10 @@ int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
	vfree(module->arch.syminfo);
	module->arch.syminfo = NULL;

	return 0;
	return module_bug_finalize(hdr, sechdrs, module);
}

void module_arch_cleanup(struct module *module)
{

	module_bug_cleanup(module);
}
+170 −18
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include <linux/fs.h>
#include <linux/ptrace.h>
#include <linux/reboot.h>
#include <linux/uaccess.h>
#include <linux/unistd.h>

#include <asm/sysreg.h>
@@ -115,39 +116,178 @@ void release_thread(struct task_struct *dead_task)
	/* do nothing */
}

static void dump_mem(const char *str, const char *log_lvl,
		     unsigned long bottom, unsigned long top)
{
	unsigned long p;
	int i;

	printk("%s%s(0x%08lx to 0x%08lx)\n", log_lvl, str, bottom, top);

	for (p = bottom & ~31; p < top; ) {
		printk("%s%04lx: ", log_lvl, p & 0xffff);

		for (i = 0; i < 8; i++, p += 4) {
			unsigned int val;

			if (p < bottom || p >= top)
				printk("         ");
			else {
				if (__get_user(val, (unsigned int __user *)p)) {
					printk("\n");
					goto out;
				}
				printk("%08x ", val);
			}
		}
		printk("\n");
	}

out:
	return;
}

static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p)
{
	return (p > (unsigned long)tinfo)
		&& (p < (unsigned long)tinfo + THREAD_SIZE - 3);
}

#ifdef CONFIG_FRAME_POINTER
static void show_trace_log_lvl(struct task_struct *tsk, unsigned long *sp,
			       struct pt_regs *regs, const char *log_lvl)
{
	unsigned long lr, fp;
	struct thread_info *tinfo;

	if (regs)
		fp = regs->r7;
	else if (tsk == current)
		asm("mov %0, r7" : "=r"(fp));
	else
		fp = tsk->thread.cpu_context.r7;

	/*
	 * Walk the stack as long as the frame pointer (a) is within
	 * the kernel stack of the task, and (b) it doesn't move
	 * downwards.
	 */
	tinfo = task_thread_info(tsk);
	printk("%sCall trace:\n", log_lvl);
	while (valid_stack_ptr(tinfo, fp)) {
		unsigned long new_fp;

		lr = *(unsigned long *)fp;
#ifdef CONFIG_KALLSYMS
		printk("%s [<%08lx>] ", log_lvl, lr);
#else
		printk(" [<%08lx>] ", lr);
#endif
		print_symbol("%s\n", lr);

		new_fp = *(unsigned long *)(fp + 4);
		if (new_fp <= fp)
			break;
		fp = new_fp;
	}
	printk("\n");
}
#else
static void show_trace_log_lvl(struct task_struct *tsk, unsigned long *sp,
			       struct pt_regs *regs, const char *log_lvl)
{
	unsigned long addr;

	printk("%sCall trace:\n", log_lvl);

	while (!kstack_end(sp)) {
		addr = *sp++;
		if (kernel_text_address(addr)) {
#ifdef CONFIG_KALLSYMS
			printk("%s [<%08lx>] ", log_lvl, addr);
#else
			printk(" [<%08lx>] ", addr);
#endif
			print_symbol("%s\n", addr);
		}
	}
	printk("\n");
}
#endif

void show_stack_log_lvl(struct task_struct *tsk, unsigned long sp,
			struct pt_regs *regs, const char *log_lvl)
{
	struct thread_info *tinfo;

	if (sp == 0) {
		if (tsk)
			sp = tsk->thread.cpu_context.ksp;
		else
			sp = (unsigned long)&tinfo;
	}
	if (!tsk)
		tsk = current;

	tinfo = task_thread_info(tsk);

	if (valid_stack_ptr(tinfo, sp)) {
		dump_mem("Stack: ", log_lvl, sp,
			 THREAD_SIZE + (unsigned long)tinfo);
		show_trace_log_lvl(tsk, (unsigned long *)sp, regs, log_lvl);
	}
}

void show_stack(struct task_struct *tsk, unsigned long *stack)
{
	show_stack_log_lvl(tsk, (unsigned long)stack, NULL, "");
}

void dump_stack(void)
{
	unsigned long stack;

	show_trace_log_lvl(current, &stack, NULL, "");
}
EXPORT_SYMBOL(dump_stack);

static const char *cpu_modes[] = {
	"Application", "Supervisor", "Interrupt level 0", "Interrupt level 1",
	"Interrupt level 2", "Interrupt level 3", "Exception", "NMI"
};

void show_regs(struct pt_regs *regs)
void show_regs_log_lvl(struct pt_regs *regs, const char *log_lvl)
{
	unsigned long sp = regs->sp;
	unsigned long lr = regs->lr;
	unsigned long mode = (regs->sr & MODE_MASK) >> MODE_SHIFT;

	if (!user_mode(regs))
	if (!user_mode(regs)) {
		sp = (unsigned long)regs + FRAME_SIZE_FULL;

		printk("%s", log_lvl);
		print_symbol("PC is at %s\n", instruction_pointer(regs));
		printk("%s", log_lvl);
		print_symbol("LR is at %s\n", lr);
	printk("pc : [<%08lx>]    lr : [<%08lx>]    %s\n"
	       "sp : %08lx  r12: %08lx  r11: %08lx\n",
	       instruction_pointer(regs),
	       lr, print_tainted(), sp, regs->r12, regs->r11);
	printk("r10: %08lx  r9 : %08lx  r8 : %08lx\n",
	       regs->r10, regs->r9, regs->r8);
	printk("r7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\n",
	       regs->r7, regs->r6, regs->r5, regs->r4);
	printk("r3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\n",
	       regs->r3, regs->r2, regs->r1, regs->r0);
	printk("Flags: %c%c%c%c%c\n",
	}

	printk("%spc : [<%08lx>]    lr : [<%08lx>]    %s\n"
	       "%ssp : %08lx  r12: %08lx  r11: %08lx\n",
	       log_lvl, instruction_pointer(regs), lr, print_tainted(),
	       log_lvl, sp, regs->r12, regs->r11);
	printk("%sr10: %08lx  r9 : %08lx  r8 : %08lx\n",
	       log_lvl, regs->r10, regs->r9, regs->r8);
	printk("%sr7 : %08lx  r6 : %08lx  r5 : %08lx  r4 : %08lx\n",
	       log_lvl, regs->r7, regs->r6, regs->r5, regs->r4);
	printk("%sr3 : %08lx  r2 : %08lx  r1 : %08lx  r0 : %08lx\n",
	       log_lvl, regs->r3, regs->r2, regs->r1, regs->r0);
	printk("%sFlags: %c%c%c%c%c\n", log_lvl,
	       regs->sr & SR_Q ? 'Q' : 'q',
	       regs->sr & SR_V ? 'V' : 'v',
	       regs->sr & SR_N ? 'N' : 'n',
	       regs->sr & SR_Z ? 'Z' : 'z',
	       regs->sr & SR_C ? 'C' : 'c');
	printk("Mode bits: %c%c%c%c%c%c%c%c%c\n",
	printk("%sMode bits: %c%c%c%c%c%c%c%c%c\n", log_lvl,
	       regs->sr & SR_H ? 'H' : 'h',
	       regs->sr & SR_R ? 'R' : 'r',
	       regs->sr & SR_J ? 'J' : 'j',
@@ -157,9 +297,21 @@ void show_regs(struct pt_regs *regs)
	       regs->sr & SR_I1M ? '1' : '.',
	       regs->sr & SR_I0M ? '0' : '.',
	       regs->sr & SR_GM ? 'G' : 'g');
	printk("CPU Mode: %s\n", cpu_modes[mode]);
	printk("%sCPU Mode: %s\n", log_lvl, cpu_modes[mode]);
	printk("%sProcess: %s [%d] (task: %p thread: %p)\n",
	       log_lvl, current->comm, current->pid, current,
	       task_thread_info(current));
}

void show_regs(struct pt_regs *regs)
{
	unsigned long sp = regs->sp;

	if (!user_mode(regs))
		sp = (unsigned long)regs + FRAME_SIZE_FULL;

	show_trace(NULL, (unsigned long *)sp, regs);
	show_regs_log_lvl(regs, "");
	show_trace_log_lvl(current, (unsigned long *)sp, regs, "");
}
EXPORT_SYMBOL(show_regs);

+127 −294
Original line number Diff line number Diff line
@@ -5,158 +5,25 @@
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#undef DEBUG
#include <linux/sched.h>

#include <linux/bug.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/sched.h>
#include <linux/uaccess.h>

#include <asm/traps.h>
#include <asm/sysreg.h>
#include <asm/addrspace.h>
#include <asm/ocd.h>
#include <asm/mmu_context.h>
#include <asm/uaccess.h>

static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
{
	unsigned long p;
	int i;

	printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);

	for (p = bottom & ~31; p < top; ) {
		printk("%04lx: ", p & 0xffff);

		for (i = 0; i < 8; i++, p += 4) {
			unsigned int val;

			if (p < bottom || p >= top)
				printk("         ");
			else {
				if (__get_user(val, (unsigned int __user *)p)) {
					printk("\n");
					goto out;
				}
				printk("%08x ", val);
			}
		}
		printk("\n");
	}

out:
	return;
}

static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p)
{
	return (p > (unsigned long)tinfo)
		&& (p < (unsigned long)tinfo + THREAD_SIZE - 3);
}

#ifdef CONFIG_FRAME_POINTER
static inline void __show_trace(struct task_struct *tsk, unsigned long *sp,
				struct pt_regs *regs)
{
	unsigned long lr, fp;
	struct thread_info *tinfo;

	tinfo = (struct thread_info *)
		((unsigned long)sp & ~(THREAD_SIZE - 1));

	if (regs)
		fp = regs->r7;
	else if (tsk == current)
		asm("mov %0, r7" : "=r"(fp));
	else
		fp = tsk->thread.cpu_context.r7;

	/*
	 * Walk the stack as long as the frame pointer (a) is within
	 * the kernel stack of the task, and (b) it doesn't move
	 * downwards.
	 */
	while (valid_stack_ptr(tinfo, fp)) {
		unsigned long new_fp;

		lr = *(unsigned long *)fp;
		printk(" [<%08lx>] ", lr);
		print_symbol("%s\n", lr);

		new_fp = *(unsigned long *)(fp + 4);
		if (new_fp <= fp)
			break;
		fp = new_fp;
	}
	printk("\n");
}
#else
static inline void __show_trace(struct task_struct *tsk, unsigned long *sp,
				struct pt_regs *regs)
{
	unsigned long addr;

	while (!kstack_end(sp)) {
		addr = *sp++;
		if (kernel_text_address(addr)) {
			printk(" [<%08lx>] ", addr);
			print_symbol("%s\n", addr);
		}
	}
}
#endif

void show_trace(struct task_struct *tsk, unsigned long *sp,
		       struct pt_regs *regs)
{
	if (regs &&
	    (((regs->sr & MODE_MASK) == MODE_EXCEPTION) ||
	     ((regs->sr & MODE_MASK) == MODE_USER)))
		return;

	printk ("Call trace:");
#ifdef CONFIG_KALLSYMS
	printk("\n");
#endif

	__show_trace(tsk, sp, regs);
	printk("\n");
}

void show_stack(struct task_struct *tsk, unsigned long *sp)
{
	unsigned long stack;

	if (!tsk)
		tsk = current;
	if (sp == 0) {
		if (tsk == current) {
			register unsigned long *real_sp __asm__("sp");
			sp = real_sp;
		} else {
			sp = (unsigned long *)tsk->thread.cpu_context.ksp;
		}
	}

	stack = (unsigned long)sp;
	dump_mem("Stack: ", stack,
		 THREAD_SIZE + (unsigned long)tsk->thread_info);
	show_trace(tsk, sp, NULL);
}

void dump_stack(void)
{
	show_stack(NULL, NULL);
}
EXPORT_SYMBOL(dump_stack);
#include <asm/ocd.h>
#include <asm/sysreg.h>
#include <asm/traps.h>

ATOMIC_NOTIFIER_HEAD(avr32_die_chain);

int register_die_notifier(struct notifier_block *nb)
{
	pr_debug("register_die_notifier: %p\n", nb);

	return atomic_notifier_chain_register(&avr32_die_chain, nb);
}
EXPORT_SYMBOL(register_die_notifier);
@@ -169,93 +36,103 @@ EXPORT_SYMBOL(unregister_die_notifier);

static DEFINE_SPINLOCK(die_lock);

void __die(const char *str, struct pt_regs *regs, unsigned long err,
	   const char *file, const char *func, unsigned long line)
void NORET_TYPE die(const char *str, struct pt_regs *regs, long err)
{
	struct task_struct *tsk = current;
	static int die_counter;

	console_verbose();
	spin_lock_irq(&die_lock);
	bust_spinlocks(1);

	printk(KERN_ALERT "%s", str);
	if (file && func)
		printk(" in %s:%s, line %ld", file, func, line);
	printk("[#%d]:\n", ++die_counter);
	print_modules();
	show_regs(regs);
	printk("Process %s (pid: %d, stack limit = 0x%p)\n",
	       tsk->comm, tsk->pid, tsk->thread_info + 1);

	if (!user_mode(regs) || in_interrupt()) {
		dump_mem("Stack: ", regs->sp,
			 THREAD_SIZE + (unsigned long)tsk->thread_info);
	printk(KERN_ALERT "Oops: %s, sig: %ld [#%d]\n" KERN_EMERG,
	       str, err, ++die_counter);
#ifdef CONFIG_PREEMPT
	printk("PREEMPT ");
#endif
#ifdef CONFIG_FRAME_POINTER
	printk("FRAME_POINTER ");
#endif
	if (current_cpu_data.features & AVR32_FEATURE_OCD) {
		unsigned long did = __mfdr(DBGREG_DID);
		printk("chip: 0x%03lx:0x%04lx rev %lu\n",
		       (did >> 1) & 0x7ff,
		       (did >> 12) & 0x7fff,
		       (did >> 28) & 0xf);
	} else {
		printk("cpu: arch %u r%u / core %u r%u\n",
		       current_cpu_data.arch_type,
		       current_cpu_data.arch_revision,
		       current_cpu_data.cpu_type,
		       current_cpu_data.cpu_revision);
	}

	print_modules();
	show_regs_log_lvl(regs, KERN_EMERG);
	show_stack_log_lvl(current, regs->sp, regs, KERN_EMERG);
	bust_spinlocks(0);
	spin_unlock_irq(&die_lock);
	do_exit(SIGSEGV);

	if (in_interrupt())
		panic("Fatal exception in interrupt");

	if (panic_on_oops)
		panic("Fatal exception");

	do_exit(err);
}

void __die_if_kernel(const char *str, struct pt_regs *regs, unsigned long err,
		     const char *file, const char *func, unsigned long line)
void _exception(long signr, struct pt_regs *regs, int code,
		unsigned long addr)
{
	siginfo_t info;

	if (!user_mode(regs))
		__die(str, regs, err, file, func, line);
}
		die("Unhandled exception in kernel mode", regs, signr);

	memset(&info, 0, sizeof(info));
	info.si_signo = signr;
	info.si_code = code;
	info.si_addr = (void __user *)addr;
	force_sig_info(signr, &info, current);

asmlinkage void do_nmi(unsigned long ecr, struct pt_regs *regs)
{
#ifdef CONFIG_SUBARCH_AVR32B
	/*
	 * The exception entry always saves RSR_EX. For NMI, this is
	 * wrong; it should be RSR_NMI
	 * Init gets no signals that it doesn't have a handler for.
	 * That's all very well, but if it has caused a synchronous
	 * exception and we ignore the resulting signal, it will just
	 * generate the same exception over and over again and we get
	 * nowhere.  Better to kill it and let the kernel panic.
	 */
	regs->sr = sysreg_read(RSR_NMI);
#endif
	if (is_init(current)) {
		__sighandler_t handler;

		spin_lock_irq(&current->sighand->siglock);
		handler = current->sighand->action[signr-1].sa.sa_handler;
		spin_unlock_irq(&current->sighand->siglock);
		if (handler == SIG_DFL) {
			/* init has generated a synchronous exception
			   and it doesn't have a handler for the signal */
			printk(KERN_CRIT "init has generated signal %ld "
			       "but has no handler for it\n", signr);
			do_exit(signr);
		}
	}
}

	printk("NMI taken!!!!\n");
	die("NMI", regs, ecr);
	BUG();
asmlinkage void do_nmi(unsigned long ecr, struct pt_regs *regs)
{
	printk(KERN_ALERT "Got Non-Maskable Interrupt, dumping regs\n");
	show_regs_log_lvl(regs, KERN_ALERT);
	show_stack_log_lvl(current, regs->sp, regs, KERN_ALERT);
}

asmlinkage void do_critical_exception(unsigned long ecr, struct pt_regs *regs)
{
	printk("Unable to handle critical exception %lu at pc = %08lx!\n",
	       ecr, regs->pc);
	die("Oops", regs, ecr);
	BUG();
	die("Critical exception", regs, SIGKILL);
}

asmlinkage void do_address_exception(unsigned long ecr, struct pt_regs *regs)
{
	siginfo_t info;

	die_if_kernel("Oops: Address exception in kernel mode", regs, ecr);

#ifdef DEBUG
	if (ecr == ECR_ADDR_ALIGN_X)
		pr_debug("Instruction Address Exception at pc = %08lx\n",
			 regs->pc);
	else if (ecr == ECR_ADDR_ALIGN_R)
		pr_debug("Data Address Exception (Read) at pc = %08lx\n",
			 regs->pc);
	else if (ecr == ECR_ADDR_ALIGN_W)
		pr_debug("Data Address Exception (Write) at pc = %08lx\n",
			 regs->pc);
	else
		BUG();

	show_regs(regs);
#endif

	info.si_signo = SIGBUS;
	info.si_errno = 0;
	info.si_code = BUS_ADRALN;
	info.si_addr = (void __user *)regs->pc;

	force_sig_info(SIGBUS, &info, current);
	_exception(SIGBUS, regs, BUS_ADRALN, regs->pc);
}

/* This way of handling undefined instructions is stolen from ARM */
@@ -280,6 +157,7 @@ static int do_cop_absent(u32 insn)
{
	int cop_nr;
	u32 cpucr;

	if ((insn & 0xfdf00000) == 0xf1900000)
		/* LDC0 */
		cop_nr = 0;
@@ -292,59 +170,55 @@ static int do_cop_absent(u32 insn)
	sysreg_write(CPUCR, cpucr);

	cpucr = sysreg_read(CPUCR);
	if ( !(cpucr & (1 << (24 + cop_nr))) ){
		printk("Coprocessor #%i not found!\n", cop_nr);
		return -1;
	}
	if (!(cpucr & (1 << (24 + cop_nr))))
		return -ENODEV;

	return 0;
}

#ifdef CONFIG_BUG
#ifdef CONFIG_DEBUG_BUGVERBOSE
static inline void do_bug_verbose(struct pt_regs *regs, u32 insn)
int is_valid_bugaddr(unsigned long pc)
{
	char *file;
	u16 line;
	char c;
	unsigned short opcode;

	if (__get_user(line, (u16 __user *)(regs->pc + 2)))
		return;
	if (__get_user(file, (char * __user *)(regs->pc + 4))
	    || (unsigned long)file < PAGE_OFFSET
	    || __get_user(c, file))
		file = "<bad filename>";

	printk(KERN_ALERT "kernel BUG at %s:%d!\n", file, line);
}
#else
static inline void do_bug_verbose(struct pt_regs *regs, u32 insn)
{
	if (pc < PAGE_OFFSET)
		return 0;
	if (probe_kernel_address((u16 *)pc, opcode))
		return 0;

	return opcode == AVR32_BUG_OPCODE;
}
#endif
#endif

asmlinkage void do_illegal_opcode(unsigned long ecr, struct pt_regs *regs)
{
	u32 insn;
	struct undef_hook *hook;
	siginfo_t info;
	void __user *pc;
	long code;

	if (!user_mode(regs))
		goto kernel_trap;
	if (!user_mode(regs) && (ecr == ECR_ILLEGAL_OPCODE)) {
		enum bug_trap_type type;

		type = report_bug(regs->pc);
		switch (type) {
		case BUG_TRAP_TYPE_NONE:
			break;
		case BUG_TRAP_TYPE_WARN:
			regs->pc += 2;
			return;
		case BUG_TRAP_TYPE_BUG:
			die("Kernel BUG", regs, SIGKILL);
		}
	}

	local_irq_enable();

	if (user_mode(regs)) {
		pc = (void __user *)instruction_pointer(regs);
	if (__get_user(insn, (u32 __user *)pc))
		if (get_user(insn, (u32 __user *)pc))
			goto invalid_area;

        if (ecr == ECR_COPROC_ABSENT) {
		if (do_cop_absent(insn) == 0)
		if (ecr == ECR_COPROC_ABSENT && !do_cop_absent(insn))
			return;
        }

		spin_lock_irq(&undef_lock);
		list_for_each_entry(hook, &undef_hook, node) {
@@ -356,72 +230,31 @@ asmlinkage void do_illegal_opcode(unsigned long ecr, struct pt_regs *regs)
			}
		}
		spin_unlock_irq(&undef_lock);

invalid_area:

#ifdef DEBUG
	printk("Illegal instruction at pc = %08lx\n", regs->pc);
	if (regs->pc < TASK_SIZE) {
		unsigned long ptbr, pgd, pte, *p;

		ptbr = sysreg_read(PTBR);
		p = (unsigned long *)ptbr;
		pgd = p[regs->pc >> 22];
		p = (unsigned long *)((pgd & 0x1ffff000) | 0x80000000);
		pte = p[(regs->pc >> 12) & 0x3ff];
		printk("page table: 0x%08lx -> 0x%08lx -> 0x%08lx\n", ptbr, pgd, pte);
	}
#endif

	info.si_signo = SIGILL;
	info.si_errno = 0;
	info.si_addr = (void __user *)regs->pc;
	switch (ecr) {
	case ECR_ILLEGAL_OPCODE:
	case ECR_UNIMPL_INSTRUCTION:
		info.si_code = ILL_ILLOPC;
		break;
	case ECR_PRIVILEGE_VIOLATION:
		info.si_code = ILL_PRVOPC;
		code = ILL_PRVOPC;
		break;
	case ECR_COPROC_ABSENT:
		info.si_code = ILL_COPROC;
		code = ILL_COPROC;
		break;
	default:
		BUG();
		code = ILL_ILLOPC;
		break;
	}

	force_sig_info(SIGILL, &info, current);
	return;

kernel_trap:
#ifdef CONFIG_BUG
	if (__kernel_text_address(instruction_pointer(regs))) {
		insn = *(u16 *)instruction_pointer(regs);
		if (insn == AVR32_BUG_OPCODE) {
			do_bug_verbose(regs, insn);
			die("Kernel BUG", regs, 0);
	_exception(SIGILL, regs, code, regs->pc);
	return;
		}
	}
#endif

	die("Oops: Illegal instruction in kernel code", regs, ecr);
invalid_area:
	_exception(SIGSEGV, regs, SEGV_MAPERR, regs->pc);
}

asmlinkage void do_fpe(unsigned long ecr, struct pt_regs *regs)
{
	siginfo_t info;

	printk("Floating-point exception at pc = %08lx\n", regs->pc);

	/* We have no FPU... */
	info.si_signo = SIGILL;
	info.si_errno = 0;
	info.si_addr = (void __user *)regs->pc;
	info.si_code = ILL_COPROC;

	force_sig_info(SIGILL, &info, current);
	/* We have no FPU yet */
	_exception(SIGILL, regs, ILL_COPROC, regs->pc);
}


+8 −1
Original line number Diff line number Diff line
@@ -26,6 +26,12 @@ SECTIONS
			_sinittext = .;
			*(.text.reset)
			*(.init.text)
			/*
			 * .exit.text is discarded at runtime, not
			 * link time, to deal with references from
			 * __bug_table
			 */
			*(.exit.text)
			_einittext = .;
		. = ALIGN(4);
		__tagtable_begin = .;
@@ -86,6 +92,8 @@ SECTIONS
		__stop___ex_table = .;
	}

	BUG_TABLE

	RODATA

	. = ALIGN(8192);
@@ -126,7 +134,6 @@ SECTIONS
	 * thrown away, as cleanup code is never called unless it's a module.
	 */
	/DISCARD/       	: {
		*(.exit.text)
		*(.exit.data)
		*(.exitcall.exit)
	}
Loading