summaryrefslogtreecommitdiffstats
path: root/sys
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
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')
-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