Coherent4.2.10/i386/msig.c
/* $Header: /ker/i386/RCS/msig.c,v 2.5 93/10/29 00:57:19 nigel Exp Locker: nigel $ */
/*
* signal handler start and return
*
* $Log: msig.c,v $
* Revision 2.5 93/10/29 00:57:19 nigel
* R98 (aka 4.2 Beta) prior to removing System Global memory
*
* Revision 2.4 93/09/02 18:11:55 nigel
* Minor edits to use new flag system
*
* Revision 2.3 93/08/19 03:40:10 nigel
* Nigel's R83
*/
#include <common/_gregset.h>
#include <kernel/sig_lib.h>
#include <sys/cmn_err.h>
#include <sys/debug.h>
#include <stddef.h>
#define _KERNEL 1
#if 0
#include <kernel/param.h>
#endif
#include <kernel/reg.h>
#include <sys/uproc.h>
#include <sys/proc.h>
void msigend ();
void msigstart ();
extern void (* ndpKfsave)();
extern void (* ndpKfrstor)();
/*
* msigstart (signum, func)
*
* signum is 1-based signal number
* func points to signal handler in user text, which is the address of a
* real handler and not a cookie such as SIG_DFL.
*
* This routine will set up the stack as shown before entering the user
* signal handler:
*
* ndp / emulator context (struct _fpstate or struct _fpemstate or absent)
* ndp / emulator flags
* previous signal mask
* fpstackframe:
* wsp (Weitek context pointer - always null, but part of BCS)
* fpsp (floating point context pointer, possibly null)
* CPU register set (SS + 1 long registers)
* 1-based signal number (user can overwrite this one)
* u.u_sigreturn (in place of user return address)
*/
/*
* A special define for signal stack arithmetic:
* Will copy at least u_sigreturn, _fpstackframe, previous mask, and ndpFlags.
* Note that _fpstackframe is an iBCS2 anomaly, not present in the ABI; below
* we define a structure with similar data and identical structure up to a
* point.
*/
struct basic_signal_frame {
__sighand_t * sf_sigreturn;
struct _fpstackframe _thank_you_intel;
/*
* From this point on is not subject to iBCS2.
*/
__sigset_t sf_signal_mask;
ulong_t sf_ndpflags;
};
#define sf_signo _thank_you_intel.signo
#define sf_regset _thank_you_intel.regs [0]
#define sf_fpsp _thank_you_intel.fpsp
#define sf_weitekp _thank_you_intel.wsp
/*
* Be careful! sf_regset yields something not quite the right size!
*/
#define SF_REGSET(rs) (* (gregset_t *) & (rs).sf_regset)
void
msigstart (signum, func, regsetp, oldmask)
int signum;
__sighand_t * func;
gregset_t * regsetp;
__sigset_t * oldmask;
{
int uesp;
int sphi, splo;
SEG * segp;
cseg_t * pp;
int sigArea; /* number of bytes written to user's stack */
struct _fpstate * fpsp;
struct basic_signal_frame
signal_frame;
/*
* The following is all highly specific to i386 tasks. Also, check
* that our notion of general-register set matches the iBCS2 cookies.
*/
ASSERT ((SS + 1) * sizeof (long) == sizeof (gregset_t));
/*
* Will copy at least u_sigreturn, _fpstackframe, and ndpFlags.
* If using ndp, need room for an _fpstate.
* If emulating, need room for an _fpemstate.
* Fp context is immediately above regular signal context.
*/
sigArea = sizeof (signal_frame);
uesp = regsetp->_i386._uesp;
if (rdNdpUser () || rdEmTrapped ()) {
fpsp = (struct _fpstate *) uesp - 1;
sigArea += sizeof (struct _fpstate);
} else
fpsp = 0;
uesp -= sigArea;
/* Add to user stack if necessary. */
segp = SELF->p_segl [SISTACK].sr_segp;
sphi = ISP_386;
splo = sphi - segp->s_size;
if (splo > uesp) {
pp = c_extend (segp->s_vmem, btocru (segp->s_size));
if (pp == 0) {
cmn_err (CE_WARN,
"Signal failed: cmd=%s c_extend (%x,%x)=0",
SELF->p_comm, (unsigned) segp->s_vmem,
btocru (segp->s_size));
return;
}
segp->s_vmem = pp;
segp->s_size += NBPC;
if (sproto (0) == 0) {
cmn_err (CE_WARN,
"Signal failed: cmd=%s sproto (0)=0",
SELF->p_comm);
return;
}
segload ();
}
/*
* Build signal stack frame locally and copy as a group.
*/
if (oldmask == NULL)
curr_signal_mask (NULL, & signal_frame.sf_signal_mask);
else
signal_frame.sf_signal_mask = * oldmask;
signal_frame.sf_weitekp = 0;
signal_frame.sf_fpsp = fpsp;
SF_REGSET (signal_frame) = * regsetp;
signal_frame.sf_signo = signum;
signal_frame.sf_sigreturn = u.u_sigreturn;
/*
* Turn off single-stepping, and set up user registers.
*/
__FLAG_REG (regsetp) =
__FLAG_CLEAR_FLAG (__FLAG_REG (regsetp), __TRAP);
__PC_REG (regsetp) = (ulong_t) func;
regsetp->_i386._uesp = uesp;
/*
* We are about to enter a signal handling function for the process.
* If current process is using ndp
* copy ndp state and related flags into signal handler stack
* mark the process as not using ndp
* arm EM traps in case signal handler uses ndp
* Else if process is using emulator
* copy emulator state and flags into signal handler stack
* mark the process as not using emulator
* Else
* put ndp / emulator flags on stack
*/
if (rdNdpUser ()) {
/* if ndp state not saved yet for this process, save it now */
if (! rdNdpSaved ()) {
ndpSave (& u.u_ndpCon);
wrNdpSaved (1);
}
signal_frame.sf_ndpflags = u.u_ndpFlags;
kucopy (& u.u_ndpCon, fpsp, sizeof (struct _fpstate));
ndpDetach ();
wrNdpUser (0);
wrNdpSaved (0);
ndpEmTraps (1);
} else {
signal_frame.sf_ndpflags = u.u_ndpFlags;
if (rdEmTrapped ()) {
if (ndpKfsave) {
unsigned long sw_old;
(* ndpKfsave) (& u.u_ndpCon, fpsp);
sw_old = getuwd (& fpsp->sw);
putuwd (& fpsp->status, sw_old);
putuwd (& fpsp->sw, sw_old & 0x7f00);
}
wrEmTrapped (0);
}
}
if (kucopy (& signal_frame, uesp, sizeof (signal_frame)) !=
sizeof (signal_frame)) {
cmn_err (CE_WARN, "Could not build signal frame");
return;
}
}
void
msigend (regset)
gregset_t regset;
{
int savedNdpFlags;
int sigNdpUser;
int temp;
__sigset_t signal_mask;
struct basic_signal_frame
* signal_framep;
/*
* Retrieved saved signal mask and ndp flags; note that the sigreturn
* and signo members of the signal frame have vanished.
*/
signal_framep = (struct basic_signal_frame *) (regset._i386._uesp -
2 * sizeof (ulong_t));
ASSERT (getuwd (& signal_framep->sf_weitekp) == 0);
temp = ukcopy (& signal_framep->sf_signal_mask, & signal_mask,
sizeof (signal_mask));
ASSERT (temp == sizeof (signal_mask));
curr_signal_mask (& signal_mask, NULL);
savedNdpFlags = getuwd (& signal_framep->sf_ndpflags);
sigNdpUser = rdNdpUser ();
u.u_ndpFlags = savedNdpFlags;
/*
* We are about to leave a signal handling function for this process.
* If signal function for this process was using ndp
* And main process was * not * using ndp
* Detach signal function from ndp
* Restore current EM to its pre-signal value.
* If main process * was * using ndp
* restore its ndp state and make it ndp owner again.
* If main process was using emulator
* restore emulator state.
*/
if (sigNdpUser && ! rdNdpUser ()) {
ndpDetach ();
ndpEmTraps (1);
}
if (rdNdpUser ()) {
ndpEmTraps (0);
ASSERT ((ulong_t) (signal_framep + 1) ==
getuwd (& signal_framep->sf_fpsp));
temp = ukcopy (signal_framep + 1, & u.u_ndpCon,
sizeof (struct _fpstate));
ASSERT (temp == sizeof (struct _fpstate));
ndpRestore (& u.u_ndpCon);
wrNdpSaved (0);
ndpMine ();
} else if (rdEmTrapped () && ndpKfrstor)
(* ndpKfrstor) (signal_framep + 1, & u.u_ndpCon);
/* Restore user process state to pre-signal values */
temp = ukcopy (& signal_framep->sf_regset, & regset, sizeof (regset));
ASSERT (temp == (SS + 1) * sizeof (long));
}