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
This commit is contained in:
Daniel Eischen 2002-11-16 06:35:53 +00:00
parent 3d8ce33a50
commit 2be05b70c9
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=106977
22 changed files with 371 additions and 55 deletions

View File

@ -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);
}
@ -2010,6 +2008,133 @@ set_regs(td, regs)
return (0);
}
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)
{

View File

@ -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);

View File

@ -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_ */

View File

@ -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]

View File

@ -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)

View File

@ -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));

View File

@ -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);
}
/*

View File

@ -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];
};

View File

@ -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_ */

View File

@ -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));

View File

@ -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

View File

@ -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);
}
/*

View File

@ -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];
};

View File

@ -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_ */

View File

@ -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));

View File

@ -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
*/

134
sys/kern/kern_context.c Normal file
View File

@ -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);
}

View File

@ -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)

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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.

View File

@ -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_ */