Coherent4.2.10/i386/msig.c

Compare this file to the similar file:
Show the results in this format:

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