summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--sys/amd64/amd64/fpu.c4
-rw-r--r--sys/amd64/amd64/machdep.c3
-rw-r--r--sys/amd64/include/signal.h4
-rw-r--r--sys/amd64/include/ucontext.h13
-rw-r--r--sys/amd64/isa/npx.c4
-rw-r--r--sys/conf/files1
-rw-r--r--sys/i386/i386/machdep.c3
-rw-r--r--sys/i386/include/signal.h4
-rw-r--r--sys/i386/include/ucontext.h13
-rw-r--r--sys/i386/isa/npx.c4
-rw-r--r--sys/ia64/ia64/machdep.c14
-rw-r--r--sys/kern/kern_context.c134
-rw-r--r--sys/kern/syscalls.master4
-rw-r--r--sys/powerpc/aim/machdep.c14
-rw-r--r--sys/powerpc/powerpc/machdep.c14
-rw-r--r--sys/sparc64/sparc64/machdep.c14
-rw-r--r--sys/sys/ucontext.h8
22 files changed, 371 insertions, 55 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)
diff --git a/sys/amd64/amd64/fpu.c b/sys/amd64/amd64/fpu.c
index 3395c99..661a698 100644
--- a/sys/amd64/amd64/fpu.c
+++ b/sys/amd64/amd64/fpu.c
@@ -161,14 +161,14 @@ void stop_emulating(void);
typedef u_char bool_t;
+static void fpusave(union savefpu *);
+static void fpurstor(union savefpu *);
static int npx_attach(device_t dev);
static void npx_identify(driver_t *driver, device_t parent);
#ifndef SMP
static void npx_intr(void *);
#endif
static int npx_probe(device_t dev);
-static void fpusave(union savefpu *);
-static void fpurstor(union savefpu *);
#ifdef I586_CPU_XXX
static long timezero(const char *funcname,
void (*func)(void *buf, size_t len));
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index 181463e..1aedc3d 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -2317,7 +2317,7 @@ set_fpregs(struct thread *td, struct fpreg *fpregs)
/*
* Get machine context.
*/
-void
+int
get_mcontext(struct thread *td, mcontext_t *mcp)
{
struct trapframe *tp;
@@ -2344,6 +2344,7 @@ get_mcontext(struct thread *td, mcontext_t *mcp)
mcp->mc_ss = tp->tf_ss;
mcp->mc_len = sizeof(*mcp);
get_fpcontext(td, mcp);
+ return (0);
}
/*
diff --git a/sys/amd64/include/signal.h b/sys/amd64/include/signal.h
index 29a9776..efc7ef0 100644
--- a/sys/amd64/include/signal.h
+++ b/sys/amd64/include/signal.h
@@ -119,7 +119,7 @@ struct sigcontext {
int sc_efl;
int sc_esp;
int sc_ss;
- int sc_len; /* sizeof(struct mcontext_t) */
+ int sc_len; /* sizeof(mcontext_t) */
/*
* XXX - See <machine/ucontext.h> and <machine/npx.h> for
* the following fields.
@@ -127,7 +127,7 @@ struct sigcontext {
int sc_fpformat;
int sc_ownedfp;
int sc_spare1[1];
- int sc_fpregs[128];
+ int sc_fpstate[128];
int sc_spare2[8];
};
diff --git a/sys/amd64/include/ucontext.h b/sys/amd64/include/ucontext.h
index af9b4fd..ea6f0b6 100644
--- a/sys/amd64/include/ucontext.h
+++ b/sys/amd64/include/ucontext.h
@@ -38,7 +38,7 @@ typedef struct __mcontext {
* and ucontext_t at the same time.
*/
int mc_onstack; /* XXX - sigcontext compat. */
- int mc_gs;
+ int mc_gs; /* machine state (trapframe) */
int mc_fs;
int mc_es;
int mc_ds;
@@ -55,7 +55,7 @@ typedef struct __mcontext {
int mc_eip;
int mc_cs;
int mc_eflags;
- int mc_esp; /* machine state */
+ int mc_esp;
int mc_ss;
int mc_len; /* sizeof(mcontext_t) */
@@ -72,8 +72,7 @@ typedef struct __mcontext {
int mc_spare2[8];
} mcontext_t;
-#ifdef _KERNEL
-#ifdef COMPAT_FREEBSD4
+#if defined(_KERNEL) && defined(COMPAT_FREEBSD4)
/* For 4.x binaries */
struct mcontext4 {
int mc_onstack; /* XXX - sigcontext compat. */
@@ -101,10 +100,4 @@ struct mcontext4 {
};
#endif
-struct thread;
-
-void get_mcontext(struct thread *td, mcontext_t *mcp);
-int set_mcontext(struct thread *td, const mcontext_t *mcp);
-#endif
-
#endif /* !_MACHINE_UCONTEXT_H_ */
diff --git a/sys/amd64/isa/npx.c b/sys/amd64/isa/npx.c
index 3395c99..661a698 100644
--- a/sys/amd64/isa/npx.c
+++ b/sys/amd64/isa/npx.c
@@ -161,14 +161,14 @@ void stop_emulating(void);
typedef u_char bool_t;
+static void fpusave(union savefpu *);
+static void fpurstor(union savefpu *);
static int npx_attach(device_t dev);
static void npx_identify(driver_t *driver, device_t parent);
#ifndef SMP
static void npx_intr(void *);
#endif
static int npx_probe(device_t dev);
-static void fpusave(union savefpu *);
-static void fpurstor(union savefpu *);
#ifdef I586_CPU_XXX
static long timezero(const char *funcname,
void (*func)(void *buf, size_t len));
diff --git a/sys/conf/files b/sys/conf/files
index 300fe54..c562b1b 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -975,6 +975,7 @@ kern/kern_alq.c optional alq
kern/kern_clock.c standard
kern/kern_condvar.c standard
kern/kern_conf.c standard
+kern/kern_context.c standard
kern/kern_descrip.c standard
kern/kern_poll.c optional device_polling
kern/kern_environment.c standard
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
index 181463e..1aedc3d 100644
--- a/sys/i386/i386/machdep.c
+++ b/sys/i386/i386/machdep.c
@@ -2317,7 +2317,7 @@ set_fpregs(struct thread *td, struct fpreg *fpregs)
/*
* Get machine context.
*/
-void
+int
get_mcontext(struct thread *td, mcontext_t *mcp)
{
struct trapframe *tp;
@@ -2344,6 +2344,7 @@ get_mcontext(struct thread *td, mcontext_t *mcp)
mcp->mc_ss = tp->tf_ss;
mcp->mc_len = sizeof(*mcp);
get_fpcontext(td, mcp);
+ return (0);
}
/*
diff --git a/sys/i386/include/signal.h b/sys/i386/include/signal.h
index 29a9776..efc7ef0 100644
--- a/sys/i386/include/signal.h
+++ b/sys/i386/include/signal.h
@@ -119,7 +119,7 @@ struct sigcontext {
int sc_efl;
int sc_esp;
int sc_ss;
- int sc_len; /* sizeof(struct mcontext_t) */
+ int sc_len; /* sizeof(mcontext_t) */
/*
* XXX - See <machine/ucontext.h> and <machine/npx.h> for
* the following fields.
@@ -127,7 +127,7 @@ struct sigcontext {
int sc_fpformat;
int sc_ownedfp;
int sc_spare1[1];
- int sc_fpregs[128];
+ int sc_fpstate[128];
int sc_spare2[8];
};
diff --git a/sys/i386/include/ucontext.h b/sys/i386/include/ucontext.h
index af9b4fd..ea6f0b6 100644
--- a/sys/i386/include/ucontext.h
+++ b/sys/i386/include/ucontext.h
@@ -38,7 +38,7 @@ typedef struct __mcontext {
* and ucontext_t at the same time.
*/
int mc_onstack; /* XXX - sigcontext compat. */
- int mc_gs;
+ int mc_gs; /* machine state (trapframe) */
int mc_fs;
int mc_es;
int mc_ds;
@@ -55,7 +55,7 @@ typedef struct __mcontext {
int mc_eip;
int mc_cs;
int mc_eflags;
- int mc_esp; /* machine state */
+ int mc_esp;
int mc_ss;
int mc_len; /* sizeof(mcontext_t) */
@@ -72,8 +72,7 @@ typedef struct __mcontext {
int mc_spare2[8];
} mcontext_t;
-#ifdef _KERNEL
-#ifdef COMPAT_FREEBSD4
+#if defined(_KERNEL) && defined(COMPAT_FREEBSD4)
/* For 4.x binaries */
struct mcontext4 {
int mc_onstack; /* XXX - sigcontext compat. */
@@ -101,10 +100,4 @@ struct mcontext4 {
};
#endif
-struct thread;
-
-void get_mcontext(struct thread *td, mcontext_t *mcp);
-int set_mcontext(struct thread *td, const mcontext_t *mcp);
-#endif
-
#endif /* !_MACHINE_UCONTEXT_H_ */
diff --git a/sys/i386/isa/npx.c b/sys/i386/isa/npx.c
index 3395c99..661a698 100644
--- a/sys/i386/isa/npx.c
+++ b/sys/i386/isa/npx.c
@@ -161,14 +161,14 @@ void stop_emulating(void);
typedef u_char bool_t;
+static void fpusave(union savefpu *);
+static void fpurstor(union savefpu *);
static int npx_attach(device_t dev);
static void npx_identify(driver_t *driver, device_t parent);
#ifndef SMP
static void npx_intr(void *);
#endif
static int npx_probe(device_t dev);
-static void fpusave(union savefpu *);
-static void fpurstor(union savefpu *);
#ifdef I586_CPU_XXX
static long timezero(const char *funcname,
void (*func)(void *buf, size_t len));
diff --git a/sys/ia64/ia64/machdep.c b/sys/ia64/ia64/machdep.c
index df7dc4a..3bb9e34 100644
--- a/sys/ia64/ia64/machdep.c
+++ b/sys/ia64/ia64/machdep.c
@@ -1038,6 +1038,20 @@ freebsd4_sigreturn(struct thread *td, struct freebsd4_sigreturn_args *uap)
}
#endif
+int
+get_mcontext(struct thread *td, mcontext_t *mcp)
+{
+
+ return (ENOSYS);
+}
+
+int
+set_mcontext(struct thread *td, const mcontext_t *mcp)
+{
+
+ return (ENOSYS);
+}
+
/*
* Machine dependent boot() routine
*/
diff --git a/sys/kern/kern_context.c b/sys/kern/kern_context.c
new file mode 100644
index 0000000..1cc0eac
--- /dev/null
+++ b/sys/kern/kern_context.c
@@ -0,0 +1,134 @@
+/*-
+ * Copyright (c) 2002 Daniel M. Eischen <deischen@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+/*
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/sysent.h>
+#include <sys/systm.h>
+#include <sys/sysproto.h>
+#include <sys/signalvar.h>
+#include <sys/ucontext.h>
+
+/*
+ * The first two fields of a ucontext_t are the signal mask and
+ * the machine context. The next field is uc_link; we want to
+ * avoid destroying the link when copying out contexts.
+ */
+#define UC_COPY_SIZE (sizeof(sigset_t) + sizeof(mcontext_t))
+
+
+#ifndef _SYS_SYSPROTO_H_
+struct getcontext_args {
+ struct __ucontext *ucp;
+}
+struct setcontext_args {
+ const struct __ucontext_t *ucp;
+}
+struct swapcontext_args {
+ struct __ucontext *oucp;
+ const struct __ucontext_t *ucp;
+}
+#endif
+
+/*
+ * MPSAFE
+ */
+int
+getcontext(struct thread *td, struct getcontext_args *uap)
+{
+ ucontext_t uc;
+ int ret;
+
+ if (uap->ucp == NULL)
+ ret = EINVAL;
+ else {
+ get_mcontext(td, &uc.uc_mcontext);
+ uc.uc_sigmask = td->td_proc->p_sigmask;
+ ret = copyout(&uc, uap->ucp, UC_COPY_SIZE);
+ }
+ return (ret);
+}
+
+/*
+ * MPSAFE
+ */
+int
+setcontext(struct thread *td, struct setcontext_args *uap)
+{
+ ucontext_t uc;
+ int ret;
+
+ if (uap->ucp == NULL)
+ ret = EINVAL;
+ else {
+ ret = copyin(uap->ucp, &uc, UC_COPY_SIZE);
+ if (ret == 0) {
+ ret = set_mcontext(td, &uc.uc_mcontext);
+ if (ret == 0) {
+ SIG_CANTMASK(uc.uc_sigmask);
+ PROC_LOCK(td->td_proc);
+ td->td_proc->p_sigmask = uc.uc_sigmask;
+ PROC_UNLOCK(td->td_proc);
+ }
+ }
+ }
+ return (ret);
+}
+
+int
+swapcontext(struct thread *td, struct swapcontext_args *uap)
+{
+ ucontext_t uc;
+ int ret;
+
+ if (uap->oucp == NULL || uap->ucp == NULL)
+ ret = EINVAL;
+ else {
+ get_mcontext(td, &uc.uc_mcontext);
+ uc.uc_sigmask = td->td_proc->p_sigmask;
+ ret = copyout(&uc, uap->oucp, UC_COPY_SIZE);
+ if (ret == 0) {
+ ret = copyin(uap->ucp, &uc, UC_COPY_SIZE);
+ if (ret == 0) {
+ ret = set_mcontext(td, &uc.uc_mcontext);
+ if (ret == 0) {
+ SIG_CANTMASK(uc.uc_sigmask);
+ PROC_LOCK(td->td_proc);
+ td->td_proc->p_sigmask = uc.uc_sigmask;
+ PROC_UNLOCK(td->td_proc);
+ }
+ }
+ }
+ }
+ return (ret);
+}
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index 650c65b..a41eb12 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -608,6 +608,10 @@
418 UNIMPL BSD __xstat
419 UNIMPL BSD __xfstat
420 UNIMPL BSD __xlstat
+421 MSTD BSD { int getcontext(struct __ucontext *ucp); }
+422 MSTD BSD { int setcontext(const struct __ucontext *ucp); }
+423 MSTD BSD { int swapcontext(struct __ucontext *oucp, \
+ const struct __ucontext *ucp); }
; Please copy any additions and changes to the following compatability tables:
; sys/ia64/ia32/syscalls.master (take a best guess)
diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c
index a14d966..ffb5070 100644
--- a/sys/powerpc/aim/machdep.c
+++ b/sys/powerpc/aim/machdep.c
@@ -638,6 +638,20 @@ freebsd4_sigreturn(struct thread *td, struct freebsd4_sigreturn_args *uap)
}
#endif
+int
+get_mcontext(struct thread *td, mcontext_t *mcp)
+{
+
+ return (ENOSYS);
+}
+
+int
+set_mcontext(struct thread *td, const mcontext_t *mcp)
+{
+
+ return (ENOSYS);
+}
+
void
cpu_boot(int howto)
{
diff --git a/sys/powerpc/powerpc/machdep.c b/sys/powerpc/powerpc/machdep.c
index a14d966..ffb5070 100644
--- a/sys/powerpc/powerpc/machdep.c
+++ b/sys/powerpc/powerpc/machdep.c
@@ -638,6 +638,20 @@ freebsd4_sigreturn(struct thread *td, struct freebsd4_sigreturn_args *uap)
}
#endif
+int
+get_mcontext(struct thread *td, mcontext_t *mcp)
+{
+
+ return (ENOSYS);
+}
+
+int
+set_mcontext(struct thread *td, const mcontext_t *mcp)
+{
+
+ return (ENOSYS);
+}
+
void
cpu_boot(int howto)
{
diff --git a/sys/sparc64/sparc64/machdep.c b/sys/sparc64/sparc64/machdep.c
index 116741b..84cf92a 100644
--- a/sys/sparc64/sparc64/machdep.c
+++ b/sys/sparc64/sparc64/machdep.c
@@ -504,6 +504,20 @@ freebsd4_sigreturn(struct thread *td, struct freebsd4_sigreturn_args *uap)
}
#endif
+int
+get_mcontext(struct thread *td, mcontext_t *mcp)
+{
+
+ return (ENOSYS);
+}
+
+int
+set_mcontext(struct thread *td, const mcontext_t *mcp)
+{
+
+ return (ENOSYS);
+}
+
/*
* Exit the kernel and execute a firmware call that will not return, as
* specified by the arguments.
diff --git a/sys/sys/ucontext.h b/sys/sys/ucontext.h
index dcce16e..1ea01d5 100644
--- a/sys/sys/ucontext.h
+++ b/sys/sys/ucontext.h
@@ -79,6 +79,14 @@ int swapcontext(ucontext_t *, const ucontext_t *);
__END_DECLS
+#else /* _KERNEL */
+
+struct thread;
+
+/* Machine-dependent functions: */
+int get_mcontext(struct thread *td, mcontext_t *mcp);
+int set_mcontext(struct thread *td, const mcontext_t *mcp);
+
#endif /* !_KERNEL */
#endif /* !_SYS_UCONTEXT_H_ */
OpenPOWER on IntegriCloud