739 lines
20 KiB
C
739 lines
20 KiB
C
/* $NetBSD: hpux_machdep.c,v 1.23 1999/08/16 02:59:23 simonb Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by Jason R. Thorpe.
|
|
*
|
|
* 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.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the NetBSD
|
|
* Foundation, Inc. and its contributors.
|
|
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 1988 University of Utah.
|
|
* Copyright (c) 1990, 1993
|
|
* The Regents of the University of California. All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to Berkeley by
|
|
* the Systems Programming Group of the University of Utah Computer
|
|
* Science Department.
|
|
*
|
|
* 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.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the University of
|
|
* California, Berkeley and its contributors.
|
|
* 4. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
|
|
*/
|
|
|
|
/*
|
|
* Machinde-dependent bits for HP-UX binary compatibility.
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/buf.h>
|
|
#include <sys/conf.h>
|
|
#include <sys/device.h>
|
|
#include <sys/exec.h>
|
|
#include <sys/file.h>
|
|
#include <sys/filedesc.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/ipc.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/namei.h>
|
|
#include <sys/poll.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/ptrace.h>
|
|
#include <sys/signalvar.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/syslog.h>
|
|
#include <sys/tty.h>
|
|
#include <sys/user.h>
|
|
#include <sys/vnode.h>
|
|
#include <sys/wait.h>
|
|
|
|
#include <machine/cpu.h>
|
|
#include <machine/reg.h>
|
|
#include <machine/psl.h>
|
|
#include <machine/vmparam.h>
|
|
|
|
#include <vm/vm.h>
|
|
#include <vm/vm_param.h>
|
|
#include <vm/vm_map.h>
|
|
|
|
#include <uvm/uvm_extern.h>
|
|
|
|
#include <sys/syscallargs.h>
|
|
|
|
#include <compat/hpux/hpux.h>
|
|
#include <compat/hpux/hpux_sig.h>
|
|
#include <compat/hpux/hpux_util.h>
|
|
#include <compat/hpux/hpux_syscall.h>
|
|
#include <compat/hpux/hpux_syscallargs.h>
|
|
|
|
#include <machine/hpux_machdep.h>
|
|
|
|
extern short exframesize[];
|
|
|
|
struct valtostr {
|
|
int val;
|
|
const char *str;
|
|
};
|
|
|
|
/*
|
|
* 6.0 and later context.
|
|
* XXX what are the HP-UX "localroot" semantics? Should we handle
|
|
* XXX diskless systems here?
|
|
*/
|
|
static const char context_040[] =
|
|
"standalone HP-MC68040 HP-MC68881 HP-MC68020 HP-MC68010 localroot default";
|
|
|
|
static const char context_fpu[] =
|
|
"standalone HP-MC68881 HP-MC68020 HP-MC68010 localroot default";
|
|
|
|
static const char context_nofpu[] =
|
|
"standalone HP-MC68020 HP-MC68010 localroot default";
|
|
|
|
static struct valtostr context_table[] = {
|
|
{ FPU_68060, &context_040[0] },
|
|
{ FPU_68040, &context_040[0] },
|
|
{ FPU_68882, &context_fpu[0] },
|
|
{ FPU_68881, &context_fpu[0] },
|
|
{ 0, NULL },
|
|
};
|
|
|
|
#define UOFF(f) ((int)&((struct user *)0)->f)
|
|
#define HPUOFF(f) ((int)&((struct hpux_user *)0)->f)
|
|
|
|
/* simplified FP structure */
|
|
struct bsdfp {
|
|
int save[54];
|
|
int reg[24];
|
|
int ctrl[3];
|
|
};
|
|
|
|
/*
|
|
* m68k-specific setup for HP-UX executables.
|
|
*/
|
|
int
|
|
hpux_cpu_makecmds(p, epp)
|
|
struct proc *p;
|
|
struct exec_package *epp;
|
|
{
|
|
/* struct hpux_exec *hpux_ep = epp->ep_hdr; */
|
|
|
|
/* set up command for exec header */
|
|
NEW_VMCMD(&epp->ep_vmcmds, hpux_cpu_vmcmd,
|
|
sizeof(struct hpux_exec), (long)epp->ep_hdr, NULLVP, 0, 0);
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* We need to stash the exec header in the pcb, so we define
|
|
* this vmcmd to do it for us, since vmcmds are executed once
|
|
* we're committed to the exec (i.e. the old program has been unmapped).
|
|
*
|
|
* The address of the header is in ev->ev_addr and the length is
|
|
* in ev->ev_len.
|
|
*/
|
|
int
|
|
hpux_cpu_vmcmd(p, ev)
|
|
struct proc *p;
|
|
struct exec_vmcmd *ev;
|
|
{
|
|
struct hpux_exec *execp = (struct hpux_exec *)ev->ev_addr;
|
|
|
|
#if 0 /* XXX - unable to handle HPUX coredumps */
|
|
/* Make sure we have room. */
|
|
if (ev->ev_len <= sizeof(p->p_addr->u_md.md_exec))
|
|
bcopy((caddr_t)ev->ev_addr, p->p_addr->u_md.md_exec,
|
|
ev->ev_len);
|
|
#endif
|
|
|
|
/* Deal with misc. HP-UX process attributes. */
|
|
if (execp->ha_trsize & HPUXM_VALID) {
|
|
if (execp->ha_trsize & HPUXM_DATAWT)
|
|
p->p_md.md_flags &= ~MDP_CCBDATA;
|
|
|
|
if (execp->ha_trsize & HPUXM_STKWT)
|
|
p->p_md.md_flags &= ~MDP_CCBSTACK;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* Return arch-type for hpux_sys_sysconf()
|
|
*/
|
|
int
|
|
hpux_cpu_sysconf_arch()
|
|
{
|
|
|
|
switch (cputype) {
|
|
case CPU_68020:
|
|
return (HPUX_SYSCONF_CPUM020);
|
|
|
|
case CPU_68030:
|
|
return (HPUX_SYSCONF_CPUM030);
|
|
|
|
default:
|
|
return (HPUX_SYSCONF_CPUM040);
|
|
}
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
/*
|
|
* HP-UX advise(2) system call.
|
|
*/
|
|
int
|
|
hpux_sys_advise(p, v, retval)
|
|
struct proc *p;
|
|
void *v;
|
|
register_t *retval;
|
|
{
|
|
struct hpux_sys_advise_args *uap = v;
|
|
int error = 0;
|
|
|
|
switch (SCARG(uap, arg)) {
|
|
case 0:
|
|
p->p_md.md_flags |= MDP_HPUXMMAP;
|
|
break;
|
|
|
|
case 1:
|
|
ICIA();
|
|
break;
|
|
|
|
case 2:
|
|
DCIA();
|
|
break;
|
|
|
|
default:
|
|
error = EINVAL;
|
|
break;
|
|
}
|
|
|
|
return (error);
|
|
}
|
|
|
|
/*
|
|
* HP-UX getcontext(2) system call.
|
|
* Man page lies, behaviour here is based on observed behaviour.
|
|
*/
|
|
int
|
|
hpux_sys_getcontext(p, v, retval)
|
|
struct proc *p;
|
|
void *v;
|
|
register_t *retval;
|
|
{
|
|
struct hpux_sys_getcontext_args *uap = v;
|
|
const char *str;
|
|
int l, i, error = 0;
|
|
int len;
|
|
|
|
for (i = 0; context_table[i].str != NULL; i++)
|
|
if (context_table[i].val == fputype)
|
|
break;
|
|
if (context_table[i].str == NULL)
|
|
str = &context_nofpu[0];
|
|
else
|
|
str = context_table[i].str;
|
|
|
|
/* + 1 ... count the terminating \0. */
|
|
l = strlen(str) + 1;
|
|
len = min(SCARG(uap, len), l);
|
|
|
|
if (len)
|
|
error = copyout(str, SCARG(uap, buf), len);
|
|
if (error == 0)
|
|
*retval = l;
|
|
return (0);
|
|
}
|
|
|
|
#if 0 /* XXX This really, really doesn't work anymore. --scottr */
|
|
/*
|
|
* Brutal hack! Map HP-UX u-area offsets into BSD k-stack offsets.
|
|
* XXX This probably doesn't work anymore, BTW. --thorpej
|
|
*/
|
|
int
|
|
hpux_to_bsd_uoff(off, isps, p)
|
|
int *off, *isps;
|
|
struct proc *p;
|
|
{
|
|
int *ar0 = p->p_md.md_regs;
|
|
struct hpux_fp *hp;
|
|
struct bsdfp *bp;
|
|
u_int raddr;
|
|
|
|
*isps = 0;
|
|
|
|
/* u_ar0 field; procxmt puts in U_ar0 */
|
|
if ((int)off == HPUOFF(hpuxu_ar0))
|
|
return(UOFF(U_ar0));
|
|
|
|
if (fputype) {
|
|
/* FP registers from PCB */
|
|
hp = (struct hpux_fp *)HPUOFF(hpuxu_fp);
|
|
bp = (struct bsdfp *)UOFF(u_pcb.pcb_fpregs);
|
|
|
|
if (off >= hp->hpfp_ctrl && off < &hp->hpfp_ctrl[3])
|
|
return((int)&bp->ctrl[off - hp->hpfp_ctrl]);
|
|
|
|
if (off >= hp->hpfp_reg && off < &hp->hpfp_reg[24])
|
|
return((int)&bp->reg[off - hp->hpfp_reg]);
|
|
}
|
|
|
|
/*
|
|
* Everything else we recognize comes from the kernel stack,
|
|
* so we convert off to an absolute address (if not already)
|
|
* for simplicity.
|
|
*/
|
|
if (off < (int *)ctob(UPAGES))
|
|
off = (int *)((u_int)off + (u_int)p->p_addr); /* XXX */
|
|
|
|
/*
|
|
* General registers.
|
|
* We know that the HP-UX registers are in the same order as ours.
|
|
* The only difference is that their PS is 2 bytes instead of a
|
|
* padded 4 like ours throwing the alignment off.
|
|
*/
|
|
if (off >= ar0 && off < &ar0[18]) {
|
|
/*
|
|
* PS: return low word and high word of PC as HP-UX would
|
|
* (e.g. &u.u_ar0[16.5]).
|
|
*
|
|
* XXX we don't do this since HP-UX adb doesn't rely on
|
|
* it and passing such an offset to procxmt will cause
|
|
* it to fail anyway. Instead, we just set the offset
|
|
* to PS and let hpux_ptrace() shift up the value returned.
|
|
*/
|
|
if (off == &ar0[PS]) {
|
|
#if 0
|
|
raddr = (u_int) &((short *)ar0)[PS*2+1];
|
|
#else
|
|
raddr = (u_int) &ar0[(int)(off - ar0)];
|
|
#endif
|
|
*isps = 1;
|
|
}
|
|
/*
|
|
* PC: off will be &u.u_ar0[16.5] since HP-UX saved PS
|
|
* is only 16 bits.
|
|
*/
|
|
else if (off == (int *)&(((short *)ar0)[PS*2+1]))
|
|
raddr = (u_int) &ar0[PC];
|
|
/*
|
|
* D0-D7, A0-A7: easy
|
|
*/
|
|
else
|
|
raddr = (u_int) &ar0[(int)(off - ar0)];
|
|
return((int)(raddr - (u_int)p->p_addr)); /* XXX */
|
|
}
|
|
|
|
/* everything else */
|
|
return (-1);
|
|
}
|
|
#endif
|
|
|
|
#define HSS_RTEFRAME 0x01
|
|
#define HSS_FPSTATE 0x02
|
|
#define HSS_USERREGS 0x04
|
|
|
|
struct hpuxsigstate {
|
|
int hss_flags; /* which of the following are valid */
|
|
struct frame hss_frame; /* original exception frame */
|
|
struct fpframe hss_fpstate; /* 68881/68882 state info */
|
|
};
|
|
|
|
/*
|
|
* WARNING: code in locore.s assumes the layout shown here for hsf_signum
|
|
* thru hsf_handler so... don't screw with them!
|
|
*/
|
|
struct hpuxsigframe {
|
|
int hsf_signum; /* signo for handler */
|
|
int hsf_code; /* additional info for handler */
|
|
struct hpuxsigcontext *hsf_scp; /* context ptr for handler */
|
|
sig_t hsf_handler; /* handler addr for u_sigc */
|
|
struct hpuxsigstate hsf_sigstate; /* state of the hardware */
|
|
struct hpuxsigcontext hsf_sc; /* actual context */
|
|
};
|
|
|
|
#ifdef DEBUG
|
|
int hpuxsigdebug = 0;
|
|
int hpuxsigpid = 0;
|
|
#define SDB_FOLLOW 0x01
|
|
#define SDB_KSTACK 0x02
|
|
#define SDB_FPSTATE 0x04
|
|
#endif
|
|
|
|
/*
|
|
* Send an interrupt to process.
|
|
*/
|
|
void
|
|
hpux_sendsig(catcher, sig, mask, code)
|
|
sig_t catcher;
|
|
int sig;
|
|
sigset_t *mask;
|
|
u_long code;
|
|
{
|
|
struct proc *p = curproc;
|
|
struct hpuxsigframe *fp, kf;
|
|
struct frame *frame;
|
|
struct sigacts *psp = p->p_sigacts;
|
|
short ft;
|
|
int onstack, fsize;
|
|
|
|
frame = (struct frame *)p->p_md.md_regs;
|
|
ft = frame->f_format;
|
|
|
|
/* Do we need to jump onto the signal stack? */
|
|
onstack =
|
|
(psp->ps_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 &&
|
|
(psp->ps_sigact[sig].sa_flags & SA_ONSTACK) != 0;
|
|
|
|
/* Allocate space for the signal handler context. */
|
|
fsize = sizeof(struct hpuxsigframe);
|
|
if (onstack)
|
|
fp = (struct hpuxsigframe *)((caddr_t)psp->ps_sigstk.ss_sp +
|
|
psp->ps_sigstk.ss_size);
|
|
else
|
|
fp = (struct hpuxsigframe *)(frame->f_regs[SP]);
|
|
fp--;
|
|
|
|
#ifdef DEBUG
|
|
if ((hpuxsigdebug & SDB_KSTACK) && p->p_pid == hpuxsigpid)
|
|
printf("hpux_sendsig(%d): sig %d ssp %p usp %p scp %p ft %d\n",
|
|
p->p_pid, sig, &onstack, fp, &fp->hsf_sc, ft);
|
|
#endif
|
|
|
|
/* Build the stack frame for the signal trampoline. */
|
|
kf.hsf_signum = bsdtohpuxsig(sig);
|
|
kf.hsf_code = code;
|
|
kf.hsf_scp = &fp->hsf_sc;
|
|
kf.hsf_handler = catcher;
|
|
|
|
/*
|
|
* Save necessary hardware state. Currently this includes:
|
|
* - general registers
|
|
* - original exception frame (if not a "normal" frame)
|
|
* - FP coprocessor state
|
|
*/
|
|
kf.hsf_sigstate.hss_flags = HSS_USERREGS;
|
|
bcopy(frame->f_regs, kf.hsf_sigstate.hss_frame.f_regs,
|
|
sizeof(frame->f_regs));
|
|
if (ft >= FMT4) {
|
|
#ifdef DEBUG
|
|
if (ft > 15 || exframesize[ft] < 0)
|
|
panic("hpux_sendsig: bogus frame type");
|
|
#endif
|
|
kf.hsf_sigstate.hss_flags |= HSS_RTEFRAME;
|
|
kf.hsf_sigstate.hss_frame.f_format = frame->f_format;
|
|
kf.hsf_sigstate.hss_frame.f_vector = frame->f_vector;
|
|
bcopy(&frame->F_u, &kf.hsf_sigstate.hss_frame.F_u,
|
|
exframesize[ft]);
|
|
/*
|
|
* Leave an indicator that we need to clean up the kernel
|
|
* stack. We do this by setting the "pad word" above the
|
|
* hardware stack frame to the amount the stack must be
|
|
* adjusted by.
|
|
*
|
|
* N.B. we increment rather than just set f_stackadj in
|
|
* case we are called from syscall when processing a
|
|
* sigreturn. In that case, f_stackadj may be non-zero.
|
|
*/
|
|
frame->f_stackadj += exframesize[ft];
|
|
frame->f_format = frame->f_vector = 0;
|
|
#ifdef DEBUG
|
|
if (hpuxsigdebug & SDB_FOLLOW)
|
|
printf("hpux_sendsig(%d): copy out %d of frame %d\n",
|
|
p->p_pid, exframesize[ft], ft);
|
|
#endif
|
|
}
|
|
|
|
if (fputype) {
|
|
kf.hsf_sigstate.hss_flags |= HSS_FPSTATE;
|
|
m68881_save(&kf.hsf_sigstate.hss_fpstate);
|
|
}
|
|
#ifdef DEBUG
|
|
if ((hpuxsigdebug & SDB_FPSTATE) &&
|
|
*(char *)&kf.hsf_sigstate.hss_fpstate)
|
|
printf("hpux_sendsig(%d): copy out FP state (%x) to %p\n",
|
|
p->p_pid, *(u_int *)&kf.hsf_sigstate.hss_fpstate,
|
|
&kf.hsf_sigstate.hss_fpstate);
|
|
#endif
|
|
|
|
/* Build the signal context to be used by hpux_sigreturn. */
|
|
kf.hsf_sc.hsc_syscall = 0; /* XXX */
|
|
kf.hsf_sc.hsc_action = 0; /* XXX */
|
|
kf.hsf_sc.hsc_pad1 = kf.hsf_sc.hsc_pad2 = 0;
|
|
kf.hsf_sc.hsc_sp = frame->f_regs[SP];
|
|
kf.hsf_sc.hsc_ps = frame->f_sr;
|
|
kf.hsf_sc.hsc_pc = frame->f_pc;
|
|
|
|
/* Save the signal stack. */
|
|
kf.hsf_sc.hsc_onstack = psp->ps_sigstk.ss_flags & SS_ONSTACK;
|
|
|
|
bsdtohpuxmask(mask, &kf.hsf_sc.hsc_mask);
|
|
|
|
/* How amazingly convenient! */
|
|
kf.hsf_sc._hsc_pad = 0;
|
|
kf.hsf_sc._hsc_ap = (int)&fp->hsf_sigstate;
|
|
|
|
if (copyout(&kf, fp, fsize)) {
|
|
#ifdef DEBUG
|
|
if ((hpuxsigdebug & SDB_KSTACK) && p->p_pid == hpuxsigpid)
|
|
printf("hpux_sendsig(%d): copyout failed on sig %d\n",
|
|
p->p_pid, sig);
|
|
#endif
|
|
/*
|
|
* Process has trashed its stack; give it an illegal
|
|
* instruction to halt it in its tracks.
|
|
*/
|
|
sigexit(p, SIGILL);
|
|
/* NOTREACHED */
|
|
}
|
|
#ifdef DEBUG
|
|
if (hpuxsigdebug & SDB_FOLLOW) {
|
|
printf(
|
|
"hpux_sendsig(%d): sig %d scp %p fp %p sc_sp %x sc_ap %x\n",
|
|
p->p_pid, sig, kf.hsf_scp, fp,
|
|
kf.hsf_sc.hsc_sp, kf.hsf_sc._hsc_ap);
|
|
}
|
|
#endif
|
|
|
|
/* Set up the registers to return to sigcode. */
|
|
frame->f_regs[SP] = (int)fp;
|
|
frame->f_pc = (int)psp->ps_sigcode;
|
|
|
|
/* Remember that we're now on the signal stack. */
|
|
if (onstack)
|
|
psp->ps_sigstk.ss_flags |= SS_ONSTACK;
|
|
|
|
#ifdef DEBUG
|
|
if ((hpuxsigdebug & SDB_KSTACK) && p->p_pid == hpuxsigpid)
|
|
printf("hpux_sendsig(%d): sig %d returns\n",
|
|
p->p_pid, sig);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* System call to cleanup state after a signal
|
|
* has been taken. Reset signal mask and
|
|
* stack state from context left by sendsig (above).
|
|
* Return to previous pc and psl as specified by
|
|
* context left by sendsig. Check carefully to
|
|
* make sure that the user has not modified the
|
|
* psl to gain improper privileges or to cause
|
|
* a machine fault.
|
|
*/
|
|
/* ARGSUSED */
|
|
int
|
|
hpux_sys_sigreturn(p, v, retval)
|
|
struct proc *p;
|
|
void *v;
|
|
register_t *retval;
|
|
{
|
|
struct hpux_sys_sigreturn_args /* {
|
|
syscallarg(struct hpuxsigcontext *) sigcntxp;
|
|
} */ *uap = v;
|
|
struct hpuxsigcontext *scp;
|
|
struct frame *frame;
|
|
struct hpuxsigcontext tsigc;
|
|
struct hpuxsigstate tstate;
|
|
int rf, flags;
|
|
|
|
/*
|
|
* The trampoline code hands us the context.
|
|
* It is unsafe to keep track of it ourselves, in the event that a
|
|
* program jumps out of a signal handler.
|
|
*/
|
|
scp = SCARG(uap, sigcntxp);
|
|
#ifdef DEBUG
|
|
if (hpuxsigdebug & SDB_FOLLOW)
|
|
printf("sigreturn: pid %d, scp %p\n", p->p_pid, scp);
|
|
#endif
|
|
if ((int)scp & 1)
|
|
return (EINVAL);
|
|
|
|
if (copyin(scp, &tsigc, sizeof(tsigc)))
|
|
return (EFAULT);
|
|
scp = &tsigc;
|
|
|
|
/* Make sure the user isn't pulling a fast one on us! */
|
|
if ((scp->hsc_ps & (PSL_MBZ|PSL_IPL|PSL_S)) != 0)
|
|
return (EINVAL);
|
|
|
|
/* Restore register context. */
|
|
frame = (struct frame *) p->p_md.md_regs;
|
|
|
|
/*
|
|
* Grab pointer tohardware state information. We have
|
|
* Squirreled this away at the end of the context structure,
|
|
* and HP-UX programs don't know about it.
|
|
*/
|
|
if ((rf = scp->_hsc_ap) == 0)
|
|
goto restore;
|
|
|
|
/*
|
|
* See if there is anything to do before we go to the
|
|
* expense of copying in close to 1/2K of data
|
|
*/
|
|
flags = fuword((caddr_t)rf);
|
|
#ifdef DEBUG
|
|
if (hpuxsigdebug & SDB_FOLLOW)
|
|
printf("hpux_sigreturn(%d): sc_ap %x flags %x\n",
|
|
p->p_pid, rf, flags);
|
|
#endif
|
|
/*
|
|
* fuword failed (bogus _hsc_ap value).
|
|
*/
|
|
if (flags == -1)
|
|
return (EINVAL);
|
|
|
|
if (flags == 0 || copyin((caddr_t)rf, (caddr_t)&tstate, sizeof tstate))
|
|
goto restore;
|
|
#ifdef DEBUG
|
|
if ((hpuxsigdebug & SDB_KSTACK) && p->p_pid == hpuxsigpid)
|
|
printf("hpux_sigreturn(%d): ssp %p usp %x scp %p ft %d\n",
|
|
p->p_pid, &flags, scp->hsc_sp, SCARG(uap, sigcntxp),
|
|
(flags & HSS_RTEFRAME) ? tstate.hss_frame.f_format : -1);
|
|
#endif
|
|
/*
|
|
* Restore long stack frames. Note that we do not copy
|
|
* back the saved SR or PC, they were picked up above from
|
|
* the sigcontext structure.
|
|
*/
|
|
if (flags & HSS_RTEFRAME) {
|
|
int sz;
|
|
|
|
/* grab frame type and validate */
|
|
sz = tstate.hss_frame.f_format;
|
|
if (sz > 15 || (sz = exframesize[sz]) < 0 ||
|
|
frame->f_stackadj < sz)
|
|
return (EINVAL);
|
|
frame->f_stackadj -= sz;
|
|
frame->f_format = tstate.hss_frame.f_format;
|
|
frame->f_vector = tstate.hss_frame.f_vector;
|
|
bcopy(&tstate.hss_frame.F_u, &frame->F_u, sz);
|
|
#ifdef DEBUG
|
|
if (hpuxsigdebug & SDB_FOLLOW)
|
|
printf("sigreturn(%d): copy in %d of frame type %d\n",
|
|
p->p_pid, sz, tstate.hss_frame.f_format);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Restore most of the users registers except for A6 and SP
|
|
* which were handled above.
|
|
*/
|
|
if (flags & HSS_USERREGS)
|
|
bcopy(tstate.hss_frame.f_regs,
|
|
frame->f_regs, sizeof(frame->f_regs) - (2 * NBPW));
|
|
|
|
/*
|
|
* Finally we restore the original FP context
|
|
*/
|
|
if (flags & HSS_FPSTATE)
|
|
m68881_restore(&tstate.hss_fpstate);
|
|
|
|
restore:
|
|
/*
|
|
* Restore the user supplied information.
|
|
*/
|
|
|
|
frame->f_regs[SP] = scp->hsc_sp;
|
|
frame->f_pc = scp->hsc_pc;
|
|
frame->f_sr = scp->hsc_ps;
|
|
|
|
if (scp->hsc_onstack & SS_ONSTACK)
|
|
p->p_sigacts->ps_sigstk.ss_flags |= SS_ONSTACK;
|
|
else
|
|
p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK;
|
|
|
|
/* Restore signal mask. */
|
|
hpuxtobsdmask(scp->hsc_mask, &p->p_sigmask);
|
|
sigminusset(&sigcantmask, &p->p_sigmask);
|
|
|
|
#ifdef DEBUG
|
|
if ((hpuxsigdebug & SDB_FPSTATE) && *(char *)&tstate.hss_fpstate)
|
|
printf("sigreturn(%d): copied in FP state (%x) at %p\n",
|
|
p->p_pid, *(u_int *)&tstate.hss_fpstate,
|
|
&tstate.hss_fpstate);
|
|
|
|
if ((hpuxsigdebug & SDB_FOLLOW) ||
|
|
((hpuxsigdebug & SDB_KSTACK) && p->p_pid == hpuxsigpid))
|
|
printf("sigreturn(%d): returns\n", p->p_pid);
|
|
#endif
|
|
return (EJUSTRETURN);
|
|
}
|
|
|
|
/*
|
|
* Set registers on exec.
|
|
*/
|
|
void
|
|
hpux_setregs(p, pack, stack)
|
|
struct proc *p;
|
|
struct exec_package *pack;
|
|
u_long stack;
|
|
{
|
|
struct frame *frame;
|
|
|
|
setregs(p, pack, stack);
|
|
|
|
frame = (struct frame *)p->p_md.md_regs;
|
|
frame->f_regs[D0] = 0; /* no float card */
|
|
frame->f_regs[D1] = fputype ? 1 : 0; /* yes/no 68881 */
|
|
frame->f_regs[A0] = 0; /* not 68010 (bit 31), no FPA (30) */
|
|
|
|
p->p_md.md_flags &= ~MDP_HPUXMMAP;
|
|
}
|