#include <asm/io.h>
#include <asm/processor.h>
#include <asm/ppcdebug.h>
+#include <asm/rtas.h>
#ifdef CONFIG_PPC_PSERIES
/* This is true if we are using the firmware NMI handler (typically LPAR) */
*/
static void FWNMI_release_errinfo(void)
{
- unsigned long ret = rtas_call(rtas_token("ibm,nmi-interlock"), 0, 1, NULL);
+ int ret = rtas_call(rtas_token("ibm,nmi-interlock"), 0, 1, NULL);
if (ret != 0)
- printk("FWNMI: nmi-interlock failed: %ld\n", ret);
+ printk("FWNMI: nmi-interlock failed: %d\n", ret);
}
#endif
info.si_errno = 0;
/* XXX something better for ECC error? */
info.si_code = BUS_ADRERR;
- info.si_addr = (void *)regs->nip;
+ info.si_addr = (void __user *)regs->nip;
printk(KERN_ERR "MCE: uncorrectable ecc error for pid %d\n",
current->pid);
_exception(SIGBUS, &info, regs);
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = 0;
- info.si_addr = 0;
+ info.si_addr = NULL;
_exception(SIGTRAP, &info, regs);
}
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = TRAP_BRKPT;
- info.si_addr = (void *)regs->nip;
+ info.si_addr = (void __user *)regs->nip;
_exception(SIGTRAP, &info, regs);
}
siginfo_t info;
unsigned long fpscr;
- if (regs->msr & MSR_FP)
- giveup_fpu(current);
+ flush_fp_to_thread(current);
fpscr = current->thread.fpscr;
info.si_signo = SIGFPE;
info.si_errno = 0;
- info.si_addr = (void *)regs->nip;
+ info.si_addr = (void __user *)regs->nip;
_exception(SIGFPE, &info, regs);
}
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = ILL_PRVOPC;
- info.si_addr = (void *)regs->nip;
+ info.si_addr = (void __user *)regs->nip;
_exception(SIGILL, &info, regs);
} else if (regs->msr & 0x20000) {
/* trap exception */
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = TRAP_BRKPT;
- info.si_addr = (void *)regs->nip;
+ info.si_addr = (void __user *)regs->nip;
_exception(SIGTRAP, &info, regs);
} else {
/* Illegal instruction */
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = ILL_ILLTRP;
- info.si_addr = (void *)regs->nip;
+ info.si_addr = (void __user *)regs->nip;
_exception(SIGILL, &info, regs);
}
}
die("Unrecoverable FP Unavailable Exception", regs, SIGABRT);
}
-void KernelAltivecUnavailableException(struct pt_regs *regs)
+void AltivecUnavailableException(struct pt_regs *regs)
{
+#ifndef CONFIG_ALTIVEC
+ if (user_mode(regs)) {
+ /* A user program has executed an altivec instruction,
+ but this kernel doesn't support altivec. */
+ siginfo_t info;
+
+ memset(&info, 0, sizeof(info));
+ info.si_signo = SIGILL;
+ info.si_code = ILL_ILLOPC;
+ info.si_addr = (void *) regs->nip;
+ _exception(SIGILL, &info, regs);
+ return;
+ }
+#endif
printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception "
"%lx at %lx\n", regs->trap, regs->nip);
die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT);
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = TRAP_TRACE;
- info.si_addr = (void *)regs->nip;
+ info.si_addr = (void __user *)regs->nip;
_exception(SIGTRAP, &info, regs);
}
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = SEGV_MAPERR;
- info.si_addr = (void *)regs->dar;
+ info.si_addr = (void __user *)regs->dar;
force_sig_info(SIGSEGV, &info, current);
} else {
/* Search exception table */
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = BUS_ADRALN;
- info.si_addr = (void *)regs->nip;
+ info.si_addr = (void __user *)regs->nip;
_exception(SIGBUS, &info, regs);
}
void
AltivecAssistException(struct pt_regs *regs)
{
- if (regs->msr & MSR_VEC)
- giveup_altivec(current);
- /* XXX quick hack for now: set the non-Java bit in the VSCR */
- current->thread.vscr.u[3] |= 0x10000;
+ int err;
+ siginfo_t info;
+
+ if (!user_mode(regs)) {
+ printk(KERN_EMERG "VMX/Altivec assist exception in kernel mode"
+ " at %lx\n", regs->nip);
+ die("Kernel VMX/Altivec assist exception", regs, SIGILL);
+ }
+
+ flush_altivec_to_thread(current);
+
+ err = emulate_altivec(regs);
+ if (err == 0) {
+ regs->nip += 4; /* skip emulated instruction */
+ emulate_single_step(regs);
+ return;
+ }
+
+ if (err == -EFAULT) {
+ /* got an error reading the instruction */
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = SEGV_MAPERR;
+ info.si_addr = (void __user *) regs->nip;
+ force_sig_info(SIGSEGV, &info, current);
+ } else {
+ /* didn't recognize the instruction */
+ /* XXX quick hack for now: set the non-Java bit in the VSCR */
+ if (printk_ratelimit())
+ printk(KERN_ERR "Unrecognized altivec instruction "
+ "in %s at %lx\n", current->comm, regs->nip);
+ current->thread.vscr.u[3] |= 0x10000;
+ }
}
#endif /* CONFIG_ALTIVEC */