aboutsummaryrefslogtreecommitdiff
path: root/sys/alpha
diff options
context:
space:
mode:
authorDaniel Eischen <deischen@FreeBSD.org>2002-11-16 06:35:53 +0000
committerDaniel Eischen <deischen@FreeBSD.org>2002-11-16 06:35:53 +0000
commit2be05b70c9be806a2e5edf3fda36628a81ed3595 (patch)
tree7153d8e405a5cd14ef74512c9e674270132975b7 /sys/alpha
parent3d8ce33a50d2ddac133ac799f4334d5b73f0b218 (diff)
Notes
Diffstat (limited to 'sys/alpha')
-rw-r--r--sys/alpha/alpha/machdep.c143
-rw-r--r--sys/alpha/include/cpu.h8
-rw-r--r--sys/alpha/include/fpu.h4
-rw-r--r--sys/alpha/include/signal.h7
-rw-r--r--sys/alpha/include/ucontext.h9
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)