summaryrefslogtreecommitdiff
path: root/sys/arch/powerpc
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/powerpc')
-rw-r--r--sys/arch/powerpc/include/pcb.h3
-rw-r--r--sys/arch/powerpc/include/psl.h3
-rw-r--r--sys/arch/powerpc/include/reg.h15
-rw-r--r--sys/arch/powerpc/include/trap.h5
-rw-r--r--sys/arch/powerpc/powerpc/trap.c180
-rw-r--r--sys/arch/powerpc/powerpc/vm_machdep.c15
6 files changed, 210 insertions, 11 deletions
diff --git a/sys/arch/powerpc/include/pcb.h b/sys/arch/powerpc/include/pcb.h
index dabc3d740c5..680e8ab545d 100644
--- a/sys/arch/powerpc/include/pcb.h
+++ b/sys/arch/powerpc/include/pcb.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pcb.h,v 1.6 2001/09/01 15:49:05 drahn Exp $ */
+/* $OpenBSD: pcb.h,v 1.7 2001/11/13 14:31:52 drahn Exp $ */
/* $NetBSD: pcb.h,v 1.1 1996/09/30 16:34:29 ws Exp $ */
/*-
@@ -57,6 +57,7 @@ struct pcb {
double fpr[32];
double fpcsr; /* FPCSR stored as double for easier access */
} pcb_fpu; /* Floating point processor */
+ struct vreg *pcb_vr; /* Vector unit */
};
struct md_coredump {
diff --git a/sys/arch/powerpc/include/psl.h b/sys/arch/powerpc/include/psl.h
index 1bf401927b8..ca74f5f959d 100644
--- a/sys/arch/powerpc/include/psl.h
+++ b/sys/arch/powerpc/include/psl.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: psl.h,v 1.4 2001/09/01 15:49:05 drahn Exp $ */
+/* $OpenBSD: psl.h,v 1.5 2001/11/13 14:31:52 drahn Exp $ */
/* $NetBSD: psl.h,v 1.1 1996/09/30 16:34:32 ws Exp $ */
/*
@@ -37,6 +37,7 @@
/*
* Flags in MSR:
*/
+#define PSL_VEC 0x02000000 /* AltiVec vector unit available */
#define PSL_POW 0x00040000
#define PSL_ILE 0x00010000
#define PSL_EE 0x00008000
diff --git a/sys/arch/powerpc/include/reg.h b/sys/arch/powerpc/include/reg.h
index d3b43ec642a..6cdf7067053 100644
--- a/sys/arch/powerpc/include/reg.h
+++ b/sys/arch/powerpc/include/reg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: reg.h,v 1.3 2001/06/29 06:07:09 drahn Exp $ */
+/* $OpenBSD: reg.h,v 1.4 2001/11/13 14:31:52 drahn Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
@@ -59,5 +59,18 @@ struct reg {
u_int32_t xer;
u_int32_t mq;
};
+
+struct vreg {
+ u_int32_t vreg[32][4];
+ u_int32_t vscr;
+ u_int32_t vrsave;
+};
+
int process_read_regs __P((struct proc *p, struct reg *regs));
+#ifdef PPC_VECTOR_SUPPORTED
+void save_vec(struct proc *);
+void enable_vec(struct proc *);
+extern struct proc *ppc_vecproc;
+extern struct pool ppc_vecpl;
+#endif /* PPC_VECTOR_SUPPORTED */
#endif /* !_POWERPC_REG_H_ */
diff --git a/sys/arch/powerpc/include/trap.h b/sys/arch/powerpc/include/trap.h
index 219cbd6b83b..a6c05ac2f3e 100644
--- a/sys/arch/powerpc/include/trap.h
+++ b/sys/arch/powerpc/include/trap.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: trap.h,v 1.4 2001/09/01 15:49:05 drahn Exp $ */
+/* $OpenBSD: trap.h,v 1.5 2001/11/13 14:31:52 drahn Exp $ */
/* $NetBSD: trap.h,v 1.1 1996/09/30 16:34:35 ws Exp $ */
/*
@@ -47,9 +47,8 @@
#define EXC_SC 0x0c00 /* System Call */
#define EXC_TRC 0x0d00 /* Trace */
#define EXC_FPA 0x0e00 /* Floating-point Assist */
-
-/* The following are only available on 604: */
#define EXC_PERF 0x0f00 /* Performance Monitoring */
+#define EXC_VEC 0x0f20 /* AltiVec Unavailable */
#define EXC_BPT 0x1300 /* Instruction Breakpoint */
#define EXC_SMI 0x1400 /* System Managment Interrupt */
diff --git a/sys/arch/powerpc/powerpc/trap.c b/sys/arch/powerpc/powerpc/trap.c
index 212858740bd..59fad7edbca 100644
--- a/sys/arch/powerpc/powerpc/trap.c
+++ b/sys/arch/powerpc/powerpc/trap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: trap.c,v 1.37 2001/11/11 04:43:53 drahn Exp $ */
+/* $OpenBSD: trap.c,v 1.38 2001/11/13 14:31:52 drahn Exp $ */
/* $NetBSD: trap.c,v 1.3 1996/10/13 03:31:37 christos Exp $ */
/*
@@ -39,6 +39,7 @@
#include <sys/systm.h>
#include <sys/user.h>
#include <sys/ktrace.h>
+#include <sys/pool.h>
#include <machine/cpu.h>
#include <machine/fpu.h>
@@ -64,6 +65,7 @@ void trap __P((struct trapframe *frame));
#define MOREARGS(sp) ((caddr_t)((int)(sp) + 8)) /* more args go here */
volatile int want_resched;
+struct proc *ppc_vecproc;
#ifdef DDB
void ppc_dumpbt __P((struct trapframe *frame));
@@ -81,6 +83,150 @@ ppc_dumpbt(struct trapframe *frame)
}
#endif
+#ifdef PPC_VECTOR_SUPPORTED
+/*
+ * Save state of the vector processor, This is done lazily in the hope
+ * that few processes in the system will be using the vector unit
+ * and that the exception time taken to switch them will be less than
+ * the necessary time to save the vector on every context switch.
+ *
+ * Also note that in this version, the VRSAVE register is saved with
+ * the state of the current process holding the vector processor,
+ * and the contents of that register are not used to optimize the save.
+ *
+ * This can lead to VRSAVE corruption, data passing between processes,
+ * because this register is accessable without the MSR[VEC] bit set.
+ * To store/restore this cleanly a processor identifier bit would need
+ * to be saved and this register saved on every context switch.
+ * Since we do not use the information, we may be able to get by
+ * with not saving it rigorously.
+ */
+void
+save_vec(struct proc *p)
+{
+ struct pcb *pcb = &p->p_addr->u_pcb;
+ u_int32_t oldmsr, msr;
+ u_int32_t tmp;
+ /* first we enable vector so that we dont throw an exception
+ * in kernel mode
+ */
+ __asm__ volatile ("mfmsr %0" : "=r" (oldmsr));
+ msr = oldmsr | PSL_VEC;
+ __asm__ volatile ("mtmsr %0" :: "r" (msr));
+ __asm__ volatile ("sync;isync");
+
+ __asm__ volatile ("mfvscr %0" : "=r" (tmp));
+ pcb->pcb_vr->vrsave = tmp;
+ __asm__ volatile ("mfspr %0, 256" : "=r" (tmp));
+ pcb->pcb_vr->vscr = tmp;
+
+ __asm__ volatile ("stvxl 0, 0, %0" ::"r" (&pcb->pcb_vr->vreg[0]));
+ __asm__ volatile ("stvxl 1, 0, %0" ::"r" (&pcb->pcb_vr->vreg[1]));
+ __asm__ volatile ("stvxl 2, 0, %0" ::"r" (&pcb->pcb_vr->vreg[2]));
+ __asm__ volatile ("stvxl 3, 0, %0" ::"r" (&pcb->pcb_vr->vreg[3]));
+ __asm__ volatile ("stvxl 4, 0, %0" ::"r" (&pcb->pcb_vr->vreg[4]));
+ __asm__ volatile ("stvxl 5, 0, %0" ::"r" (&pcb->pcb_vr->vreg[5]));
+ __asm__ volatile ("stvxl 6, 0, %0" ::"r" (&pcb->pcb_vr->vreg[6]));
+ __asm__ volatile ("stvxl 7, 0, %0" ::"r" (&pcb->pcb_vr->vreg[7]));
+ __asm__ volatile ("stvxl 8, 0, %0" ::"r" (&pcb->pcb_vr->vreg[8]));
+ __asm__ volatile ("stvxl 9, 0, %0" ::"r" (&pcb->pcb_vr->vreg[9]));
+ __asm__ volatile ("stvxl 10, 0, %0" ::"r" (&pcb->pcb_vr->vreg[10]));
+ __asm__ volatile ("stvxl 11, 0, %0" ::"r" (&pcb->pcb_vr->vreg[11]));
+ __asm__ volatile ("stvxl 12, 0, %0" ::"r" (&pcb->pcb_vr->vreg[12]));
+ __asm__ volatile ("stvxl 13, 0, %0" ::"r" (&pcb->pcb_vr->vreg[13]));
+ __asm__ volatile ("stvxl 14, 0, %0" ::"r" (&pcb->pcb_vr->vreg[14]));
+ __asm__ volatile ("stvxl 15, 0, %0" ::"r" (&pcb->pcb_vr->vreg[15]));
+ __asm__ volatile ("stvxl 16, 0, %0" ::"r" (&pcb->pcb_vr->vreg[16]));
+ __asm__ volatile ("stvxl 17, 0, %0" ::"r" (&pcb->pcb_vr->vreg[17]));
+ __asm__ volatile ("stvxl 18, 0, %0" ::"r" (&pcb->pcb_vr->vreg[18]));
+ __asm__ volatile ("stvxl 19, 0, %0" ::"r" (&pcb->pcb_vr->vreg[19]));
+ __asm__ volatile ("stvxl 20, 0, %0" ::"r" (&pcb->pcb_vr->vreg[20]));
+ __asm__ volatile ("stvxl 21, 0, %0" ::"r" (&pcb->pcb_vr->vreg[21]));
+ __asm__ volatile ("stvxl 22, 0, %0" ::"r" (&pcb->pcb_vr->vreg[22]));
+ __asm__ volatile ("stvxl 23, 0, %0" ::"r" (&pcb->pcb_vr->vreg[23]));
+ __asm__ volatile ("stvxl 24, 0, %0" ::"r" (&pcb->pcb_vr->vreg[24]));
+ __asm__ volatile ("stvxl 25, 0, %0" ::"r" (&pcb->pcb_vr->vreg[25]));
+ __asm__ volatile ("stvxl 26, 0, %0" ::"r" (&pcb->pcb_vr->vreg[26]));
+ __asm__ volatile ("stvxl 27, 0, %0" ::"r" (&pcb->pcb_vr->vreg[27]));
+ __asm__ volatile ("stvxl 28, 0, %0" ::"r" (&pcb->pcb_vr->vreg[28]));
+ __asm__ volatile ("stvxl 29, 0, %0" ::"r" (&pcb->pcb_vr->vreg[29]));
+ __asm__ volatile ("stvxl 30, 0, %0" ::"r" (&pcb->pcb_vr->vreg[30]));
+ __asm__ volatile ("stvxl 31, 0, %0" ::"r" (&pcb->pcb_vr->vreg[31]));
+
+ /* fix kernel msr back */
+ __asm__ volatile ("mfmsr %0" :: "r" (oldmsr));
+}
+
+/*
+ * Copy the context of a given process into the vector registers.
+ */
+void
+enable_vec(struct proc *p)
+{
+ struct pcb *pcb = &p->p_addr->u_pcb;
+ u_int32_t oldmsr, msr;
+ u_int32_t tmp;
+
+ /* If this is the very first altivec instruction executed
+ * by this process, create a context.
+ */
+ if (pcb->pcb_vr == NULL) {
+ pcb->pcb_vr = pool_get(&ppc_vecpl, PR_WAITOK);
+ bzero(pcb->pcb_vr, sizeof *(pcb->pcb_vr));
+ }
+
+ /* first we enable vector so that we dont throw an exception
+ * in kernel mode
+ */
+ __asm__ volatile ("mfmsr %0" : "=r" (oldmsr));
+ msr = oldmsr | PSL_VEC;
+ __asm__ volatile ("mtmsr %0" :: "r" (msr));
+ __asm__ volatile ("sync;isync");
+
+ tmp = pcb->pcb_vr->vrsave;
+ __asm__ volatile ("mtvscr %0" :: "r" (tmp));
+ tmp = pcb->pcb_vr->vscr;
+ __asm__ volatile ("mtspr 256, %0" :: "r" (tmp));
+
+ __asm__ volatile ("lvxl 0, 0, %0" ::"r" (&pcb->pcb_vr->vreg[0]));
+ __asm__ volatile ("lvxl 1, 0, %0" ::"r" (&pcb->pcb_vr->vreg[1]));
+ __asm__ volatile ("lvxl 2, 0, %0" ::"r" (&pcb->pcb_vr->vreg[2]));
+ __asm__ volatile ("lvxl 3, 0, %0" ::"r" (&pcb->pcb_vr->vreg[3]));
+ __asm__ volatile ("lvxl 4, 0, %0" ::"r" (&pcb->pcb_vr->vreg[4]));
+ __asm__ volatile ("lvxl 5, 0, %0" ::"r" (&pcb->pcb_vr->vreg[5]));
+ __asm__ volatile ("lvxl 6, 0, %0" ::"r" (&pcb->pcb_vr->vreg[6]));
+ __asm__ volatile ("lvxl 7, 0, %0" ::"r" (&pcb->pcb_vr->vreg[7]));
+ __asm__ volatile ("lvxl 8, 0, %0" ::"r" (&pcb->pcb_vr->vreg[8]));
+ __asm__ volatile ("lvxl 9, 0, %0" ::"r" (&pcb->pcb_vr->vreg[9]));
+ __asm__ volatile ("lvxl 10, 0, %0" ::"r" (&pcb->pcb_vr->vreg[10]));
+ __asm__ volatile ("lvxl 11, 0, %0" ::"r" (&pcb->pcb_vr->vreg[11]));
+ __asm__ volatile ("lvxl 12, 0, %0" ::"r" (&pcb->pcb_vr->vreg[12]));
+ __asm__ volatile ("lvxl 13, 0, %0" ::"r" (&pcb->pcb_vr->vreg[13]));
+ __asm__ volatile ("lvxl 14, 0, %0" ::"r" (&pcb->pcb_vr->vreg[14]));
+ __asm__ volatile ("lvxl 15, 0, %0" ::"r" (&pcb->pcb_vr->vreg[15]));
+ __asm__ volatile ("lvxl 16, 0, %0" ::"r" (&pcb->pcb_vr->vreg[16]));
+ __asm__ volatile ("lvxl 17, 0, %0" ::"r" (&pcb->pcb_vr->vreg[17]));
+ __asm__ volatile ("lvxl 18, 0, %0" ::"r" (&pcb->pcb_vr->vreg[18]));
+ __asm__ volatile ("lvxl 19, 0, %0" ::"r" (&pcb->pcb_vr->vreg[19]));
+ __asm__ volatile ("lvxl 20, 0, %0" ::"r" (&pcb->pcb_vr->vreg[20]));
+ __asm__ volatile ("lvxl 21, 0, %0" ::"r" (&pcb->pcb_vr->vreg[21]));
+ __asm__ volatile ("lvxl 22, 0, %0" ::"r" (&pcb->pcb_vr->vreg[22]));
+ __asm__ volatile ("lvxl 23, 0, %0" ::"r" (&pcb->pcb_vr->vreg[23]));
+ __asm__ volatile ("lvxl 24, 0, %0" ::"r" (&pcb->pcb_vr->vreg[24]));
+ __asm__ volatile ("lvxl 25, 0, %0" ::"r" (&pcb->pcb_vr->vreg[25]));
+ __asm__ volatile ("lvxl 26, 0, %0" ::"r" (&pcb->pcb_vr->vreg[26]));
+ __asm__ volatile ("lvxl 27, 0, %0" ::"r" (&pcb->pcb_vr->vreg[27]));
+ __asm__ volatile ("lvxl 28, 0, %0" ::"r" (&pcb->pcb_vr->vreg[28]));
+ __asm__ volatile ("lvxl 29, 0, %0" ::"r" (&pcb->pcb_vr->vreg[29]));
+ __asm__ volatile ("lvxl 30, 0, %0" ::"r" (&pcb->pcb_vr->vreg[30]));
+ __asm__ volatile ("lvxl 31, 0, %0" ::"r" (&pcb->pcb_vr->vreg[31]));
+
+ /* fix kernel msr back */
+ __asm__ volatile ("mfmsr %0" :: "r" (oldmsr));
+}
+#endif /* PPC_VECTOR_SUPPORTED */
+
+
void
trap(frame)
struct trapframe *frame;
@@ -412,12 +558,22 @@ for (i = 0; i < errnum; i++) {
break;
/* This is not really a perf exception, but is an ALTIVEC unavail
- * which we do not handle, kill the process with illegal instruction.
+ * if we do not handle it, kill the process with illegal instruction.
*/
case EXC_PERF|EXC_USER:
+#ifdef PPC_VECTOR_SUPPORTED
+ case EXC_VEC|EXC_USER:
+ if (ppc_vecproc) {
+ save_vec(ppc_vecproc);
+ }
+ ppc_vecproc = p;
+ enable_vec(p);
+ break;
+#else /* PPC_VECTOR_SUPPORTED */
sv.sival_int = frame->srr0;
trapsignal(p, SIGILL, 0, ILL_ILLOPC, sv);
break;
+#endif /* PPC_VECTOR_SUPPORTED */
case EXC_AST|EXC_USER:
/* This is just here that we trap */
@@ -465,8 +621,23 @@ for (i = 0; i < errnum; i++) {
/*
* If someone stole the fpu while we were away, disable it
*/
- if (p != fpuproc)
+ if (p != fpuproc) {
frame->srr1 &= ~PSL_FP;
+ } else {
+ frame->srr1 |= PSL_FP;
+ }
+
+#ifdef PPC_VECTOR_SUPPORTED
+ /*
+ * If someone stole the vector unit while we were away, disable it
+ */
+ if (p != ppc_vecproc) {
+ frame->srr1 &= ~PSL_VEC;
+ } else {
+ frame->srr1 |= PSL_VEC;
+ }
+#endif /* PPC_VECTOR_SUPPORTED */
+
curpriority = p->p_priority;
}
@@ -481,7 +652,8 @@ child_return(arg)
tf->fixreg[FIRSTARG] = 0;
tf->fixreg[FIRSTARG + 1] = 1;
tf->cr &= ~0x10000000;
- tf->srr1 &= ~PSL_FP; /* Disable FPU, as we can't be fpuproc */
+ /* Disable FPU, VECT, as we can't be fpuproc */
+ tf->srr1 &= ~(PSL_FP|PSL_VEC);
#ifdef KTRACE
if (KTRPOINT(p, KTR_SYSRET))
ktrsysret(p, SYS_fork, 0, 0);
diff --git a/sys/arch/powerpc/powerpc/vm_machdep.c b/sys/arch/powerpc/powerpc/vm_machdep.c
index 6d03dc5785d..e86c63b6971 100644
--- a/sys/arch/powerpc/powerpc/vm_machdep.c
+++ b/sys/arch/powerpc/powerpc/vm_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: vm_machdep.c,v 1.26 2001/11/06 19:53:16 miod Exp $ */
+/* $OpenBSD: vm_machdep.c,v 1.27 2001/11/13 14:31:52 drahn Exp $ */
/* $NetBSD: vm_machdep.c,v 1.1 1996/09/30 16:34:57 ws Exp $ */
/*
@@ -34,6 +34,7 @@
#include <sys/param.h>
#include <sys/core.h>
#include <sys/exec.h>
+#include <sys/pool.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
#include <sys/user.h>
@@ -66,6 +67,18 @@ cpu_fork(p1, p2, stack, stacksize, func, arg)
save_fpu(p1);
*pcb = p1->p_addr->u_pcb;
+#ifdef PPC_VECTOR_SUPPORTED
+ /* ALTIVEC */
+ if (p1->p_addr->u_pcb.pcb_vr != NULL) {
+ if (p1 == ppc_vecproc)
+ save_vec(p1);
+ pcb->pcb_vr = pool_get(&ppc_vecpl, PR_WAITOK);
+ *pcb->pcb_vr = *p1->p_addr->u_pcb.pcb_vr;
+ } else {
+ pcb->pcb_vr = NULL;
+ }
+#endif /* PPC_VECTOR_SUPPORTED */
+
pcb->pcb_pm = p2->p_vmspace->vm_map.pmap;
pmap_extract(pmap_kernel(),