293 lines
7.7 KiB
C
293 lines
7.7 KiB
C
/* $NetBSD: irix_exec.c,v 1.41 2005/03/26 05:12:35 fvdl Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 2001-2002 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by Emmanuel Dreyfus.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
__KERNEL_RCSID(0, "$NetBSD: irix_exec.c,v 1.41 2005/03/26 05:12:35 fvdl Exp $");
|
|
|
|
#ifdef _KERNEL_OPT
|
|
#include "opt_syscall_debug.h"
|
|
#endif
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/lock.h>
|
|
#include <sys/exec.h>
|
|
#include <sys/types.h>
|
|
#include <sys/malloc.h>
|
|
|
|
#include <machine/regnum.h>
|
|
#include <uvm/uvm_extern.h>
|
|
|
|
#include <compat/irix/irix_syscall.h>
|
|
#include <compat/irix/irix_types.h>
|
|
#include <compat/irix/irix_exec.h>
|
|
#include <compat/irix/irix_prctl.h>
|
|
#include <compat/irix/irix_signal.h>
|
|
#include <compat/irix/irix_errno.h>
|
|
#include <compat/irix/irix_sysctl.h>
|
|
#include <compat/irix/irix_usema.h>
|
|
|
|
extern const int native_to_svr4_signo[];
|
|
|
|
static void irix_e_proc_exec __P((struct proc *, struct exec_package *));
|
|
static void irix_e_proc_fork __P((struct proc *, struct proc *, int));
|
|
static void irix_e_proc_exit __P((struct proc *));
|
|
static void irix_e_proc_init __P((struct proc *, struct vmspace *));
|
|
|
|
extern struct sysent irix_sysent[];
|
|
extern const char * const irix_syscallnames[];
|
|
|
|
#ifndef __HAVE_SYSCALL_INTERN
|
|
void irix_syscall __P((void));
|
|
#else
|
|
void irix_syscall_intern __P((struct proc *));
|
|
#endif
|
|
|
|
/*
|
|
* Fake sigcode. COMPAT_IRIX does not use it, since the
|
|
* signal trampoline is provided by libc. However, some
|
|
* other part of the kernel will be happier if we still
|
|
* provide non NULL sigcode and esigcode.
|
|
*/
|
|
char irix_sigcode[] = { 0 };
|
|
|
|
const struct emul emul_irix = {
|
|
"irix",
|
|
"/emul/irix",
|
|
#ifndef __HAVE_MINIMAL_EMUL
|
|
0,
|
|
native_to_irix_errno,
|
|
IRIX_SYS_syscall,
|
|
IRIX_SYS_NSYSENT,
|
|
#endif
|
|
irix_sysent,
|
|
#ifdef SYSCALL_DEBUG
|
|
irix_syscallnames,
|
|
#else
|
|
NULL,
|
|
#endif
|
|
irix_sendsig,
|
|
trapsignal,
|
|
NULL,
|
|
irix_sigcode,
|
|
irix_sigcode,
|
|
NULL,
|
|
setregs,
|
|
irix_e_proc_exec,
|
|
irix_e_proc_fork,
|
|
irix_e_proc_exit,
|
|
NULL,
|
|
NULL,
|
|
#ifdef __HAVE_SYSCALL_INTERN
|
|
irix_syscall_intern,
|
|
#else
|
|
irix_syscall,
|
|
#endif
|
|
NULL,
|
|
irix_vm_fault,
|
|
|
|
uvm_default_mapaddr,
|
|
};
|
|
|
|
/*
|
|
* set registers on exec for N32 applications
|
|
*/
|
|
void
|
|
irix_n32_setregs(l, pack, stack)
|
|
struct lwp *l;
|
|
struct exec_package *pack;
|
|
u_long stack;
|
|
{
|
|
struct frame *f = (struct frame *)l->l_md.md_regs;
|
|
|
|
/* Enable 64 bit instructions (eg: sd) */
|
|
f->f_regs[_R_SR] |= MIPS3_SR_UX;
|
|
}
|
|
|
|
/*
|
|
* per-process emuldata allocation
|
|
*/
|
|
static void
|
|
irix_e_proc_init(p, vmspace)
|
|
struct proc *p;
|
|
struct vmspace *vmspace;
|
|
{
|
|
struct irix_emuldata *ied;
|
|
vaddr_t vm_min;
|
|
vsize_t vm_len;
|
|
|
|
if (!p->p_emuldata)
|
|
p->p_emuldata = malloc(sizeof(struct irix_emuldata),
|
|
M_EMULDATA, M_WAITOK | M_ZERO);
|
|
|
|
ied = p->p_emuldata;
|
|
ied->ied_p = p;
|
|
|
|
LIST_INIT(&ied->ied_shared_regions);
|
|
vm_min = vm_map_min(&vmspace->vm_map);
|
|
vm_len = vm_map_max(&vmspace->vm_map) - vm_min;
|
|
irix_isrr_insert(vm_min, vm_len, IRIX_ISRR_SHARED, p);
|
|
}
|
|
|
|
/*
|
|
* exec() hook used to allocate per process structures
|
|
*/
|
|
static void
|
|
irix_e_proc_exec(p, epp)
|
|
struct proc *p;
|
|
struct exec_package *epp;
|
|
{
|
|
int error;
|
|
|
|
irix_e_proc_init(p, p->p_vmspace);
|
|
|
|
/* Initialize the process private area (PRDA) */
|
|
error = irix_prda_init(p);
|
|
#ifdef DEBUG_IRIX
|
|
if (error != 0)
|
|
printf("irix_e_proc_exec(): PRDA map failed ");
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* exit() hook used to free per process data structures
|
|
*/
|
|
static void
|
|
irix_e_proc_exit(p)
|
|
struct proc *p;
|
|
{
|
|
struct proc *pp;
|
|
struct irix_emuldata *ied;
|
|
struct irix_share_group *isg;
|
|
struct irix_shared_regions_rec *isrr;
|
|
|
|
/*
|
|
* Send SIGHUP to child process as requested using prctl(2)
|
|
*/
|
|
proclist_lock_read();
|
|
PROCLIST_FOREACH(pp, &allproc) {
|
|
/* Select IRIX processes */
|
|
if (irix_check_exec(pp) == 0)
|
|
continue;
|
|
|
|
ied = (struct irix_emuldata *)(pp->p_emuldata);
|
|
if (ied->ied_termchild && pp->p_pptr == p)
|
|
psignal(pp, native_to_svr4_signo[SIGHUP]);
|
|
}
|
|
proclist_unlock_read();
|
|
|
|
/*
|
|
* Remove the process from share group processes list, if revelant.
|
|
*/
|
|
ied = (struct irix_emuldata *)(p->p_emuldata);
|
|
|
|
if ((isg = ied->ied_share_group) != NULL) {
|
|
lockmgr(&isg->isg_lock, LK_EXCLUSIVE, NULL);
|
|
LIST_REMOVE(ied, ied_sglist);
|
|
isg->isg_refcount--;
|
|
|
|
if (isg->isg_refcount == 0) {
|
|
/*
|
|
* This was the last process in the share group.
|
|
* Call irix_usema_exit_cleanup() to free in-kernel
|
|
* structures hold by the share group through
|
|
* the irix_usync_cntl system call.
|
|
*/
|
|
irix_usema_exit_cleanup(p, NULL);
|
|
/*
|
|
* Free the share group structure (no need to free
|
|
* the lock since we destroy it now).
|
|
*/
|
|
free(isg, M_EMULDATA);
|
|
ied->ied_share_group = NULL;
|
|
} else {
|
|
/*
|
|
* There are other processes remaining in the share
|
|
* group. Call irix_usema_exit_cleanup() to set the
|
|
* first of them as the owner of the structures
|
|
* hold in the kernel by the share group.
|
|
*/
|
|
irix_usema_exit_cleanup(p,
|
|
LIST_FIRST(&isg->isg_head)->ied_p);
|
|
lockmgr(&isg->isg_lock, LK_RELEASE, NULL);
|
|
}
|
|
|
|
} else {
|
|
/*
|
|
* The process is not part of a share group. Call
|
|
* irix_usema_exit_cleanup() to free in-kernel structures hold
|
|
* by the process through the irix_usync_cntl system call.
|
|
*/
|
|
irix_usema_exit_cleanup(p, NULL);
|
|
}
|
|
|
|
/* Free (un)shared region list */
|
|
while (!LIST_EMPTY(&ied->ied_shared_regions)) {
|
|
isrr = LIST_FIRST(&ied->ied_shared_regions);
|
|
LIST_REMOVE(isrr , isrr_list);
|
|
free(isrr, M_EMULDATA);
|
|
}
|
|
|
|
free(p->p_emuldata, M_EMULDATA);
|
|
p->p_emuldata = NULL;
|
|
}
|
|
|
|
/*
|
|
* fork() hook used to allocate per process structures
|
|
*/
|
|
static void
|
|
irix_e_proc_fork(p, parent, forkflags)
|
|
struct proc *p, *parent;
|
|
int forkflags;
|
|
{
|
|
struct irix_emuldata *ied1;
|
|
struct irix_emuldata *ied2;
|
|
|
|
p->p_emuldata = NULL;
|
|
|
|
/* Use parent's vmspace because our vmspace may not be setup yet */
|
|
irix_e_proc_init(p, parent->p_vmspace);
|
|
|
|
ied1 = p->p_emuldata;
|
|
ied2 = parent->p_emuldata;
|
|
|
|
(void) memcpy(ied1, ied2, (unsigned)
|
|
((caddr_t)&ied1->ied_endcopy - (caddr_t)&ied1->ied_startcopy));
|
|
}
|