diff options
-rw-r--r-- | sys/sparc64/include/pcb.h | 3 | ||||
-rw-r--r-- | sys/sparc64/sparc64/exception.S | 4 | ||||
-rw-r--r-- | sys/sparc64/sparc64/genassym.c | 2 | ||||
-rw-r--r-- | sys/sparc64/sparc64/machdep.c | 38 | ||||
-rw-r--r-- | sys/sparc64/sparc64/swtch.S | 3 |
5 files changed, 46 insertions, 4 deletions
diff --git a/sys/sparc64/include/pcb.h b/sys/sparc64/include/pcb.h index c1e00f1..93615ba 100644 --- a/sys/sparc64/include/pcb.h +++ b/sys/sparc64/include/pcb.h @@ -33,11 +33,14 @@ #define MAXWIN 8 +#define PCB_FEF (1 << 0) + /* NOTE: pcb_ufp must be aligned on a 64 byte boundary. */ struct pcb { uint32_t pcb_ufp[64]; u_long pcb_sp; u_long pcb_pc; + u_long pcb_flags; u_long pcb_nsaved; u_long pcb_rwsp[MAXWIN]; struct rwindow pcb_rw[MAXWIN]; diff --git a/sys/sparc64/sparc64/exception.S b/sys/sparc64/sparc64/exception.S index 3a4cb6c..cc0444b 100644 --- a/sys/sparc64/sparc64/exception.S +++ b/sys/sparc64/sparc64/exception.S @@ -1183,6 +1183,10 @@ END(tl0_sftrap) .endm ENTRY(tl0_fp_restore) + ldx [PCB_REG + PCB_FLAGS], %g1 + andn %g1, PCB_FEF, %g1 + stx %g1, [PCB_REG + PCB_FLAGS] + wr %g0, FPRS_FEF, %fprs wr %g0, ASI_BLK_S, %asi ldda [PCB_REG + PCB_UFP + (0 * 64)] %asi, %f0 diff --git a/sys/sparc64/sparc64/genassym.c b/sys/sparc64/sparc64/genassym.c index b0389b9..e014d97 100644 --- a/sys/sparc64/sparc64/genassym.c +++ b/sys/sparc64/sparc64/genassym.c @@ -246,9 +246,11 @@ ASSYM(PCB_SIZEOF, sizeof(struct pcb)); ASSYM(PCB_UFP, offsetof(struct pcb, pcb_ufp)); ASSYM(PCB_SP, offsetof(struct pcb, pcb_sp)); ASSYM(PCB_PC, offsetof(struct pcb, pcb_pc)); +ASSYM(PCB_FLAGS, offsetof(struct pcb, pcb_flags)); ASSYM(PCB_NSAVED, offsetof(struct pcb, pcb_nsaved)); ASSYM(PCB_RWSP, offsetof(struct pcb, pcb_rwsp)); ASSYM(PCB_RW, offsetof(struct pcb, pcb_rw)); +ASSYM(PCB_FEF, PCB_FEF); ASSYM(VM_PMAP, offsetof(struct vmspace, vm_pmap)); ASSYM(PM_ACTIVE, offsetof(struct pmap, pm_active)); diff --git a/sys/sparc64/sparc64/machdep.c b/sys/sparc64/sparc64/machdep.c index 04c4865..45d6c7c 100644 --- a/sys/sparc64/sparc64/machdep.c +++ b/sys/sparc64/sparc64/machdep.c @@ -513,17 +513,47 @@ freebsd4_sigreturn(struct thread *td, struct freebsd4_sigreturn_args *uap) #endif int -get_mcontext(struct thread *td, mcontext_t *mcp) +get_mcontext(struct thread *td, mcontext_t *mc) { + struct trapframe *tf; + struct pcb *pcb; - return (ENOSYS); + if (((uintptr_t)mc & (64 - 1)) != 0) + return (EINVAL); + tf = td->td_frame; + pcb = td->td_pcb; + bcopy(tf, mc, sizeof(*tf)); + critical_enter(); + if ((tf->tf_fprs & FPRS_FEF) != 0) + savefpctx(mc->mc_fp); + else if ((pcb->pcb_flags & PCB_FEF) != 0) { + bcopy(pcb->pcb_ufp, mc->mc_fp, sizeof(*mc->mc_fp)); + mc->mc_fprs |= FPRS_FEF; + } + critical_exit(); + return (0); } int -set_mcontext(struct thread *td, const mcontext_t *mcp) +set_mcontext(struct thread *td, const mcontext_t *mc) { + struct trapframe *tf; + struct pcb *pcb; + uint64_t wstate; - return (ENOSYS); + if (!TSTATE_SECURE(mc->mc_tstate)) + return (EINVAL); + tf = td->td_frame; + pcb = td->td_pcb; + wstate = tf->tf_wstate; + bcopy(mc, tf, sizeof(*tf)); + tf->tf_wstate = wstate; + if ((mc->mc_fprs & FPRS_FEF) != 0) { + tf->tf_fprs = 0; + bcopy(mc->mc_fp, pcb->pcb_ufp, sizeof(*pcb->pcb_ufp)); + pcb->pcb_flags |= PCB_FEF; + } + return (0); } /* diff --git a/sys/sparc64/sparc64/swtch.S b/sys/sparc64/sparc64/swtch.S index 402928d..d506a07 100644 --- a/sys/sparc64/sparc64/swtch.S +++ b/sys/sparc64/sparc64/swtch.S @@ -76,6 +76,9 @@ ENTRY(cpu_switch) wr %g0, 0, %fprs andn %l3, FPRS_FEF, %l3 stx %l3, [%l2 + TF_FPRS] + ldx [%l1 + PCB_FLAGS], %l3 + or %l3, PCB_FEF, %l3 + stx %l3, [%l1 + PCB_FLAGS] /* * Flush the windows out to the stack and save the current frame |