diff options
| author | Daniel Eischen <deischen@FreeBSD.org> | 2002-11-16 06:35:53 +0000 |
|---|---|---|
| committer | Daniel Eischen <deischen@FreeBSD.org> | 2002-11-16 06:35:53 +0000 |
| commit | 2be05b70c9be806a2e5edf3fda36628a81ed3595 (patch) | |
| tree | 7153d8e405a5cd14ef74512c9e674270132975b7 /sys/alpha | |
| parent | 3d8ce33a50d2ddac133ac799f4334d5b73f0b218 (diff) | |
Notes
Diffstat (limited to 'sys/alpha')
| -rw-r--r-- | sys/alpha/alpha/machdep.c | 143 | ||||
| -rw-r--r-- | sys/alpha/include/cpu.h | 8 | ||||
| -rw-r--r-- | sys/alpha/include/fpu.h | 4 | ||||
| -rw-r--r-- | sys/alpha/include/signal.h | 7 | ||||
| -rw-r--r-- | sys/alpha/include/ucontext.h | 9 |
5 files changed, 148 insertions, 23 deletions
diff --git a/sys/alpha/alpha/machdep.c b/sys/alpha/alpha/machdep.c index 7a4a001e2c47..ddf67d7016ff 100644 --- a/sys/alpha/alpha/machdep.c +++ b/sys/alpha/alpha/machdep.c @@ -210,7 +210,9 @@ static void freebsd4_sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code); #endif +static void get_fpcontext(struct thread *td, mcontext_t *mcp); static void identifycpu(void); +static int set_fpcontext(struct thread *td, const mcontext_t *mcp); struct kva_md_info kmi; @@ -1405,7 +1407,7 @@ sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) frame->tf_regs[FRAME_TRAPARG_A1]; sf.sf_uc.uc_mcontext.mc_regs[R_TRAPARG_A2] = frame->tf_regs[FRAME_TRAPARG_A2]; - sf.sf_uc.uc_mcontext.mc_format = __UC_REV0_SIGFRAME; + sf.sf_uc.uc_mcontext.mc_format = _MC_REV0_SIGFRAME; /* * Allocate and validate space for the signal handler @@ -1664,13 +1666,15 @@ sigreturn(struct thread *td, return (error); } #ifdef COMPAT_43 - if (((struct osigcontext*)&uc)->sc_regs[R_ZERO] == 0xACEDBADE) - return osigreturn(td, (struct osigreturn_args *)uap); + if (((struct osigcontext*)&uc)->sc_regs[R_ZERO] == 0xACEDBADE) + return osigreturn(td, (struct osigreturn_args *)uap); #endif /* * Restore the user-supplied information */ + if ((error = set_fpcontext(td, &uc.uc_mcontext)) != 0) + return (error); set_regs(td, (struct reg *)uc.uc_mcontext.mc_regs); val = (uc.uc_mcontext.mc_regs[R_PS] | ALPHA_PSL_USERSET) & ~ALPHA_PSL_USERCLR; @@ -1692,12 +1696,6 @@ sigreturn(struct thread *td, signotify(p); PROC_UNLOCK(p); - /* XXX ksc.sc_ownedfp ? */ - alpha_fpstate_drop(td); - bcopy((struct fpreg *)uc.uc_mcontext.mc_fpregs, - &td->td_pcb->pcb_fp, sizeof(struct fpreg)); - td->td_pcb->pcb_fp_control = uc.uc_mcontext.mc_fp_control; - return (EJUSTRETURN); } @@ -2011,6 +2009,133 @@ set_regs(td, regs) } int +get_mcontext(struct thread *td, mcontext_t *mcp) +{ + /* + * Use a trapframe for getsetcontext, so just copy the + * threads trapframe. + */ + bcopy(&td->td_frame, &mcp->mc_regs, sizeof(td->td_frame)); + + /* + * When the thread is the current thread, the user stack pointer + * is not in the PCB; it must be read from the PAL. + */ + if (td == curthread) + mcp->mc_regs[FRAME_SP] = alpha_pal_rdusp(); + + mcp->mc_format = _MC_REV0_TRAPFRAME; + mcp->mc_onstack = sigonstack(alpha_pal_rdusp()) ? 1 : 0; + get_fpcontext(td, mcp); + return (0); +} + +int +set_mcontext(struct thread *td, const mcontext_t *mcp) +{ + int ret; + unsigned long val; + + if ((mcp->mc_format != _MC_REV0_TRAPFRAME) && + (mcp->mc_format != _MC_REV0_SIGFRAME)) + return (EINVAL); + else if ((ret = set_fpcontext(td, mcp)) != 0) + return (ret); + + if (mcp->mc_format == _MC_REV0_SIGFRAME) { + set_regs(td, (struct reg *)&mcp->mc_regs); + val = (mcp->mc_regs[R_PS] | ALPHA_PSL_USERSET) & + ~ALPHA_PSL_USERCLR; + td->td_frame->tf_regs[FRAME_PS] = val; + td->td_frame->tf_regs[FRAME_PC] = mcp->mc_regs[R_PC]; + td->td_frame->tf_regs[FRAME_FLAGS] = 0; + if (td == curthread) + alpha_pal_wrusp(mcp->mc_regs[R_SP]); + + } else { + if (td == curthread) + alpha_pal_wrusp(mcp->mc_regs[FRAME_SP]); + /* + * The context is a trapframe, so just copy it over the + * threads frame. + */ + bcopy(&mcp->mc_regs, &td->td_frame, sizeof(td->td_frame)); + } + return (0); +} + +static void +get_fpcontext(struct thread *td, mcontext_t *mcp) +{ + register_t s; + + s = intr_disable(); + if ((td->td_md.md_flags & MDTD_FPUSED) == 0) { + intr_restore(s); + mcp->mc_ownedfp = _MC_FPOWNED_NONE; + } else if (PCPU_GET(fpcurthread) == td) { + /* See comments in alpha_fpstate_save() regarding FEN. */ + if (td != curthread) + alpha_pal_wrfen(1); + /* + * The last field (fpr_cr) of struct fpreg isn't + * included in mc_fpregs, but it immediately follows + * it in mcontext_t. + */ + savefpstate((struct fpreg *)&mcp->mc_fpregs); + if (td != curthread) + alpha_pal_wrfen(0); + intr_restore(s); + mcp->mc_ownedfp = _MC_FPOWNED_FPU; + } else { + /* + * The thread doesn't own the FPU so get the state from + * the PCB. + */ + intr_restore(s); + bcopy(&td->td_pcb->pcb_fp, &mcp->mc_fpregs, + sizeof(td->td_pcb->pcb_fp)); + mcp->mc_ownedfp = _MC_FPOWNED_PCB; + } + /* There's no harm in always doing the following. */ + mcp->mc_fp_control = td->td_pcb->pcb_fp_control; +} + +static int +set_fpcontext(struct thread *td, const mcontext_t *mcp) +{ + register_t s; + + if (mcp->mc_ownedfp == _MC_FPOWNED_NONE) { + /* XXX - Drop fpu state so we get a clean state? */ + alpha_fpstate_drop(td); + } + else if ((mcp->mc_ownedfp != _MC_FPOWNED_FPU) && + (mcp->mc_ownedfp != _MC_FPOWNED_PCB)) + return (EINVAL); + else { + s = intr_disable(); + if (PCPU_GET(fpcurthread) == td) { + /* + * The last field (fpr_cr) of struct fpreg isn't + * included in mc_fpregs, but it immediately follows + * it in mcontext_t. + */ + restorefpstate((struct fpreg *)&mcp->mc_fpregs); + intr_restore(s); + } + else { + /* Just save the state in the PCB. */ + intr_restore(s); + bcopy(&mcp->mc_fpregs, &td->td_pcb->pcb_fp, + sizeof (td->td_pcb->pcb_fp)); + } + td->td_pcb->pcb_fp_control = mcp->mc_fp_control; + } + return (0); +} + +int fill_dbregs(struct thread *td, struct dbreg *dbregs) { diff --git a/sys/alpha/include/cpu.h b/sys/alpha/include/cpu.h index 9d05765251ff..0e39182233a6 100644 --- a/sys/alpha/include/cpu.h +++ b/sys/alpha/include/cpu.h @@ -115,11 +115,11 @@ void XentRestart(void); /* MAGIC */ void XentSys(u_int64_t, u_int64_t, u_int64_t); /* MAGIC */ void XentUna(u_int64_t, u_int64_t, u_int64_t); /* MAGIC */ void alpha_init(u_long, u_long, u_long, u_long, u_long); +void alpha_fpstate_check(struct thread *td); +void alpha_fpstate_drop(struct thread *td); +void alpha_fpstate_save(struct thread *td, int write); +void alpha_fpstate_switch(struct thread *td); int alpha_pa_access(u_long); -void alpha_fpstate_check(struct thread *p); -void alpha_fpstate_save(struct thread *p, int write); -void alpha_fpstate_drop(struct thread *p); -void alpha_fpstate_switch(struct thread *p); int badaddr (void *, size_t); int badaddr_read(void *, size_t, void *); u_int64_t console_restart(u_int64_t, u_int64_t, u_int64_t); diff --git a/sys/alpha/include/fpu.h b/sys/alpha/include/fpu.h index 712a1f96a252..9f4800feeea1 100644 --- a/sys/alpha/include/fpu.h +++ b/sys/alpha/include/fpu.h @@ -116,9 +116,7 @@ __asm__("trapb") #ifdef _KERNEL - -extern int fp_software_completion(u_int64_t regmask, struct thread *p); - +extern int fp_software_completion(u_int64_t regmask, struct thread *td); #endif #endif /* ! _MACHINE_FPU_H_ */ diff --git a/sys/alpha/include/signal.h b/sys/alpha/include/signal.h index 2a1f17b9b2d5..37a969efb5e9 100644 --- a/sys/alpha/include/signal.h +++ b/sys/alpha/include/signal.h @@ -94,10 +94,9 @@ struct sigcontext { unsigned long sc_fpregs[32]; /* FP register set (see above) */ unsigned long sc_fpcr; /* FP control register (see above) */ unsigned long sc_fp_control; /* FP software control word */ - long sc_ownedfp; /* fp has been used */ - long sc_xxx1[2]; /* sc_ssize, sc_sbase on DUX */ - long sc_xxx2[3]; /* sc_fp_trap_pc, sc_fp_trigger_sum, sc_fp_trigger_inst */ - long sc_reserved[2]; /* XXX */ + long sc_ownedfp; /* fp has been used; see mcontext_t */ + long sc_format; /* see mcontext_t */ + long sc_spare[6]; /* XXX */ }; #define sc_sp sc_regs[R_SP] diff --git a/sys/alpha/include/ucontext.h b/sys/alpha/include/ucontext.h index bfc18df8f42f..2c3ed7053a72 100644 --- a/sys/alpha/include/ucontext.h +++ b/sys/alpha/include/ucontext.h @@ -43,11 +43,14 @@ typedef struct __mcontext { unsigned long mc_fpregs[32]; unsigned long mc_fpcr; unsigned long mc_fp_control; +#define _MC_FPOWNED_NONE 0 /* FP state not used */ +#define _MC_FPOWNED_FPU 1 /* FP state came from FPU */ +#define _MC_FPOWNED_PCB 2 /* FP state came from PCB */ long mc_ownedfp; -#define __UC_REV0_SIGFRAME 1 /* context is a signal frame */ -#define __UC_REV0_TRAPFRAME 2 /* context is a trap frame */ +#define _MC_REV0_SIGFRAME 1 /* context is a signal frame */ +#define _MC_REV0_TRAPFRAME 2 /* context is a trap frame */ long mc_format; - long __spare__[6]; + long mc_spare[6]; } mcontext_t; #if defined(_KERNEL) && defined(COMPAT_FREEBSD4) |
