diff options
Diffstat (limited to 'sys/arch/powerpc')
-rw-r--r-- | sys/arch/powerpc/include/pcb.h | 3 | ||||
-rw-r--r-- | sys/arch/powerpc/include/psl.h | 3 | ||||
-rw-r--r-- | sys/arch/powerpc/include/reg.h | 15 | ||||
-rw-r--r-- | sys/arch/powerpc/include/trap.h | 5 | ||||
-rw-r--r-- | sys/arch/powerpc/powerpc/trap.c | 180 | ||||
-rw-r--r-- | sys/arch/powerpc/powerpc/vm_machdep.c | 15 |
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(), |