#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/prctl.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
do_exit(err);
}
-void
-_exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
+void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
{
siginfo_t info;
info.si_signo = signr;
info.si_errno = 0;
info.si_code = code;
- info.si_addr = (void *) addr;
+ info.si_addr = (void __user *) addr;
force_sig_info(signr, &info, current);
}
/* On 4xx, the reason for the machine check or program exception
is in the ESR. */
#define get_reason(regs) ((regs)->dsisr)
+#ifndef CONFIG_E500
+#define get_mc_reason(regs) ((regs)->dsisr)
+#else
+#define get_mc_reason(regs) (mfspr(SPRN_MCSR))
+#endif
#define REASON_FP 0
#define REASON_ILLEGAL ESR_PIL
#define REASON_PRIVILEGED ESR_PPR
/* On non-4xx, the reason for the machine check or program
exception is in the MSR. */
#define get_reason(regs) ((regs)->msr)
+#define get_mc_reason(regs) ((regs)->msr)
#define REASON_FP 0x100000
#define REASON_ILLEGAL 0x80000
#define REASON_PRIVILEGED 0x40000
#define clear_single_step(regs) ((regs)->msr &= ~MSR_SE)
#endif
-void
-MachineCheckException(struct pt_regs *regs)
+void MachineCheckException(struct pt_regs *regs)
{
- unsigned long reason = get_reason(regs);
+ unsigned long reason = get_mc_reason(regs);
if (user_mode(regs)) {
regs->msr |= MSR_RI;
/* Clear MCSR */
mtspr(SPRN_MCSR, mcsr);
}
-#else /* !CONFIG_4xx */
+#elif defined (CONFIG_E500)
+ printk("Machine check in kernel mode.\n");
+ printk("Caused by (from MCSR=%lx): ", reason);
+
+ if (reason & MCSR_MCP)
+ printk("Machine Check Signal\n");
+ if (reason & MCSR_ICPERR)
+ printk("Instruction Cache Parity Error\n");
+ if (reason & MCSR_DCP_PERR)
+ printk("Data Cache Push Parity Error\n");
+ if (reason & MCSR_DCPERR)
+ printk("Data Cache Parity Error\n");
+ if (reason & MCSR_GL_CI)
+ printk("Guarded Load or Cache-Inhibited stwcx.\n");
+ if (reason & MCSR_BUS_IAERR)
+ printk("Bus - Instruction Address Error\n");
+ if (reason & MCSR_BUS_RAERR)
+ printk("Bus - Read Address Error\n");
+ if (reason & MCSR_BUS_WAERR)
+ printk("Bus - Write Address Error\n");
+ if (reason & MCSR_BUS_IBERR)
+ printk("Bus - Instruction Data Error\n");
+ if (reason & MCSR_BUS_RBERR)
+ printk("Bus - Read Data Bus Error\n");
+ if (reason & MCSR_BUS_WBERR)
+ printk("Bus - Read Data Bus Error\n");
+ if (reason & MCSR_BUS_IPERR)
+ printk("Bus - Instruction Parity Error\n");
+ if (reason & MCSR_BUS_RPERR)
+ printk("Bus - Read Parity Error\n");
+#else /* !CONFIG_4xx && !CONFIG_E500 */
printk("Machine check in kernel mode.\n");
printk("Caused by (from SRR1=%lx): ", reason);
switch (reason & 0x601F0000) {
die("machine check", regs, SIGBUS);
}
-void
-SMIException(struct pt_regs *regs)
+void SMIException(struct pt_regs *regs)
{
debugger(regs);
#if !(defined(CONFIG_XMON) || defined(CONFIG_KGDB))
#endif
}
-void
-UnknownException(struct pt_regs *regs)
+void UnknownException(struct pt_regs *regs)
{
printk("Bad trap at PC: %lx, MSR: %lx, vector=%lx %s\n",
regs->nip, regs->msr, regs->trap, print_tainted());
_exception(SIGTRAP, regs, 0, 0);
}
-void
-InstructionBreakpoint(struct pt_regs *regs)
+void InstructionBreakpoint(struct pt_regs *regs)
{
if (debugger_iabr_match(regs))
return;
_exception(SIGTRAP, regs, TRAP_BRKPT, 0);
}
-void
-RunModeException(struct pt_regs *regs)
+void RunModeException(struct pt_regs *regs)
{
_exception(SIGTRAP, regs, 0, 0);
}
#define INST_MFSPR_PVR 0x7c1f42a6
#define INST_MFSPR_PVR_MASK 0xfc1fffff
-static int
-emulate_instruction(struct pt_regs *regs)
+static int emulate_instruction(struct pt_regs *regs)
{
u32 instword;
u32 rd;
return module_find_bug(bugaddr);
}
-int
-check_bug_trap(struct pt_regs *regs)
+int check_bug_trap(struct pt_regs *regs)
{
struct bug_entry *bug;
unsigned long addr;
return 0;
}
-void
-ProgramCheckException(struct pt_regs *regs)
+void ProgramCheckException(struct pt_regs *regs)
{
unsigned int reason = get_reason(regs);
extern int do_mathemu(struct pt_regs *regs);
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
}
-void
-SingleStepException(struct pt_regs *regs)
+void SingleStepException(struct pt_regs *regs)
{
regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */
if (debugger_sstep(regs))
_exception(SIGTRAP, regs, TRAP_TRACE, 0);
}
-void
-AlignmentException(struct pt_regs *regs)
+void AlignmentException(struct pt_regs *regs)
{
int fixed;
_exception(SIGBUS, regs, BUS_ADRALN, regs->dar);
}
-void
-StackOverflow(struct pt_regs *regs)
+void StackOverflow(struct pt_regs *regs)
{
printk(KERN_CRIT "Kernel stack overflow in process %p, r1=%lx\n",
current, regs->gpr[1]);
die("nonrecoverable exception", regs, SIGKILL);
}
-void
-trace_syscall(struct pt_regs *regs)
+void trace_syscall(struct pt_regs *regs)
{
printk("Task: %p(%d), PC: %08lX/%08lX, Syscall: %3ld, Result: %s%ld %s\n",
current, current->pid, regs->nip, regs->link, regs->gpr[0],
}
#ifdef CONFIG_8xx
-void
-SoftwareEmulation(struct pt_regs *regs)
+void SoftwareEmulation(struct pt_regs *regs)
{
extern int do_mathemu(struct pt_regs *);
extern int Soft_emulate_8xx(struct pt_regs *);
#endif /* CONFIG_4xx || CONFIG_BOOKE */
#if !defined(CONFIG_TAU_INT)
-void
-TAUException(struct pt_regs *regs)
+void TAUException(struct pt_regs *regs)
{
printk("TAU trap at PC: %lx, MSR: %lx, vector=%lx %s\n",
regs->nip, regs->msr, regs->trap, print_tainted());
/* The kernel has executed an altivec instruction without
first enabling altivec. Whinge but let it do it. */
if (++kernel_altivec_count < 10)
- printk(KERN_ERR "AltiVec used in kernel (task=%p, pc=%x)\n",
+ printk(KERN_ERR "AltiVec used in kernel (task=%p, pc=%lx)\n",
current, regs->nip);
regs->msr |= MSR_VEC;
}
#ifdef CONFIG_ALTIVEC
-void
-AltivecAssistException(struct pt_regs *regs)
+void AltivecAssistException(struct pt_regs *regs)
{
int err;
}
#endif /* CONFIG_ALTIVEC */
+#ifdef CONFIG_FSL_BOOKE
+void CacheLockingException(struct pt_regs *regs, unsigned long address,
+ unsigned long error_code)
+{
+ /* We treat cache locking instructions from the user
+ * as priv ops, in the future we could try to do
+ * something smarter
+ */
+ if (error_code & (ESR_DLK|ESR_ILK))
+ _exception(SIGILL, regs, ILL_PRVOPC, regs->nip);
+ return;
+}
+#endif /* CONFIG_FSL_BOOKE */
+
+#ifdef CONFIG_SPE
+void SPEFloatingPointException(struct pt_regs *regs)
+{
+ unsigned long spefscr;
+ int fpexc_mode;
+ int code = 0;
+
+ spefscr = current->thread.spefscr;
+ fpexc_mode = current->thread.fpexc_mode;
+
+ /* Hardware does not neccessarily set sticky
+ * underflow/overflow/invalid flags */
+ if ((spefscr & SPEFSCR_FOVF) && (fpexc_mode & PR_FP_EXC_OVF)) {
+ code = FPE_FLTOVF;
+ spefscr |= SPEFSCR_FOVFS;
+ }
+ else if ((spefscr & SPEFSCR_FUNF) && (fpexc_mode & PR_FP_EXC_UND)) {
+ code = FPE_FLTUND;
+ spefscr |= SPEFSCR_FUNFS;
+ }
+ else if ((spefscr & SPEFSCR_FDBZ) && (fpexc_mode & PR_FP_EXC_DIV))
+ code = FPE_FLTDIV;
+ else if ((spefscr & SPEFSCR_FINV) && (fpexc_mode & PR_FP_EXC_INV)) {
+ code = FPE_FLTINV;
+ spefscr |= SPEFSCR_FINVS;
+ }
+ else if ((spefscr & (SPEFSCR_FG | SPEFSCR_FX)) && (fpexc_mode & PR_FP_EXC_RES))
+ code = FPE_FLTRES;
+
+ current->thread.spefscr = spefscr;
+
+ _exception(SIGFPE, regs, code, regs->nip);
+ return;
+}
+#endif
void __init trap_init(void)
{