summaryrefslogtreecommitdiffstats
path: root/sys/alpha
diff options
context:
space:
mode:
authordeischen <deischen@FreeBSD.org>2002-11-16 06:35:53 +0000
committerdeischen <deischen@FreeBSD.org>2002-11-16 06:35:53 +0000
commit31ea801074585bde84b74ea76bbedd715ad2f3a4 (patch)
tree7153d8e405a5cd14ef74512c9e674270132975b7 /sys/alpha
parenta858c2cb5c0438dd0886b2672ecba35cc82bf1dc (diff)
downloadFreeBSD-src-31ea801074585bde84b74ea76bbedd715ad2f3a4.zip
FreeBSD-src-31ea801074585bde84b74ea76bbedd715ad2f3a4.tar.gz
Add getcontext, setcontext, and swapcontext as system calls.
Previously these were libc functions but were requested to be made into system calls for atomicity and to coalesce what might be two entrances into the kernel (signal mask setting and floating point trap) into one. A few style nits and comments from bde are also included. Tested on alpha by: gallatin
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 7a4a001..ddf67d7 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 9d05765..0e39182 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 712a1f9..9f4800f 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 2a1f17b..37a969e 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 bfc18df..2c3ed70 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)
OpenPOWER on IntegriCloud