NetBSD-5.0.2/sys/arch/powerpc/powerpc/darwin_machdep.c

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

/*	$NetBSD: darwin_machdep.c,v 1.25 2008/04/28 20:23:32 martin Exp $ */

/*-
 * Copyright (c) 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.
 *
 * 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: darwin_machdep.c,v 1.25 2008/04/28 20:23:32 martin Exp $");

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/mount.h>
#include <sys/signal.h>

#include <compat/sys/signal.h>
#include <compat/sys/signalvar.h>

#include <compat/mach/mach_types.h>
#include <compat/mach/mach_vm.h>

#include <compat/darwin/darwin_audit.h>
#include <compat/darwin/darwin_signal.h>
#include <compat/darwin/darwin_syscallargs.h>

#include <machine/psl.h>
#include <machine/darwin_machdep.h>

/* 
 * First argument is in reg 3, duplicated from 
 * sys/arch/powerpc/powerpc/syscall.c 
 */
#define FIRSTARG 3

/*
 * Send a signal to a Darwin process.
 */
void
darwin_sendsig(ksi, mask)
	const ksiginfo_t *ksi;
	const sigset_t *mask;
{
	struct lwp *l = curlwp;
	struct proc *p = l->l_proc;
	struct sigacts *ps = p->p_sigacts;
	struct trapframe *tf;
	struct darwin_sigframe *sfp, sf;
	int onstack;
	size_t stack_size;
	sig_t catcher;
	int sig;
	int error;

	tf = trapframe(l);

	sig = ksi->ksi_signo;
	catcher = SIGACTION(p, sig).sa_handler;

	/* Use an alternate signal stack? */
	onstack =
	    (l->l_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 &&
	    (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0;

	/* Set the new stack pointer sfp */
	if (onstack) {
		sfp = (struct darwin_sigframe *)
		    ((char *)l->l_sigstk.ss_sp +
		    l->l_sigstk.ss_size);
		stack_size = l->l_sigstk.ss_size;
	} else {
		sfp = (struct darwin_sigframe *)tf->fixreg[1];
		stack_size = 0;
	}
	/* 16 bytes alignement */
	sfp = (struct darwin_sigframe *)((u_long)(sfp - 1) & ~0xfUL);

	/* Prepare the signal frame */
	bzero(&sf, sizeof(sf));
	sf.dmc.es.dar = tf->dar;
	sf.dmc.es.dsisr = tf->dsisr;
	sf.dmc.es.exception = tf->exc;

	sf.dmc.ss.srr0 = tf->srr0;
	sf.dmc.ss.srr1 = tf->srr1 & PSL_USERSRR1;
	memcpy(&sf.dmc.ss.gpreg[0], &tf->fixreg[0], sizeof(sf.dmc.ss.gpreg));
	sf.dmc.ss.cr = tf->cr;
	sf.dmc.ss.xer = tf->xer;
	sf.dmc.ss.lr = tf->lr;
	sf.dmc.ss.ctr = tf->ctr;
	sf.dmc.ss.mq = 0; /* XXX */

	/* XXX What should we do with th FP regs? */

	/* 
	 * Darwin only supports 32 signals. 
	 * Unsupported signals are mapped to 0 
	 */
	if (sig >= 32) {
		DPRINTF(("unsupported signal for darwin: %d\n", sig));
		sig = 0;
	}

	native_to_darwin_siginfo(ksi, &sf.duc.si);
	sf.duc.uctx.uc_onstack = onstack;
	native_sigset_to_sigset13(mask, &sf.duc.uctx.uc_sigmask);
	sf.duc.uctx.uc_stack.ss_sp = (char *)sfp;
	sf.duc.uctx.uc_stack.ss_size = stack_size;
	if (onstack)
		sf.duc.uctx.uc_stack.ss_flags |= SS_ONSTACK;
	sf.duc.uctx.uc_link = l->l_ctxlink;
	sf.duc.uctx.uc_mcsize = sizeof(sf.dmc);
	sf.duc.uctx.uc_mcontext = (struct darwin_mcontext *)&sfp->dmc;

	/* Copyout mcontext */
	if ((error = copyout(&sf.dmc, &sfp->dmc, sizeof(sf.dmc))) != 0) {
		sigexit(l, SIGILL);
		/* NOTREACHED */
	}

	/* Copyout ucontext */
	if ((error = copyout(&sf.duc, &sfp->duc, sizeof(sf.duc))) != 0) {
		sigexit(l, SIGILL);
		/* NOTREACHED */
	}

	/* Darwin only supports libc based trampoline */
	if (ps->sa_sigdesc[sig].sd_vers != 1) {
		sigexit(l, SIGILL);
		/* NOTREACHED */
	}

	/* Prepare registers */
	tf->fixreg[1] = (u_long)sfp;
	tf->fixreg[3] = (u_long)catcher;
	if (SIGACTION(p, sig).sa_flags & SA_SIGINFO)
		tf->fixreg[4] = 2; /* with siginfo */
	else
		tf->fixreg[4] = 1; /* without siginfo */
	tf->fixreg[5] = (u_long)sig;
	tf->fixreg[6] = (u_long)&sfp->duc.si;
	tf->fixreg[7] = (u_long)&sfp->duc.uctx;
	tf->lr = (u_long)tf->srr0;
	tf->srr0 = (u_long)ps->sa_sigdesc[sig].sd_tramp;
	tf->srr1 = (PSL_EE | PSL_ME | PSL_IR | PSL_DR | PSL_PR);

	/* Remember that we're now on the signal stack. */
	if (onstack)
		l->l_sigstk.ss_flags |= SS_ONSTACK;

	return;
}

/*
 * The signal trampoline calls this system call 
 * to get the process state restored like it was
 * before the signal delivery.
 * 
 * This is the version for X.2 binaries and older
 */
int
darwin_sys_sigreturn_x2(struct lwp *l, const struct darwin_sys_sigreturn_x2_args *uap, register_t *retval)
{
	/* {
		syscallarg(struct darwin_ucontext *) uctx;
	} */
	struct darwin_ucontext uctx;
	struct darwin_mcontext mctx;
	struct trapframe *tf;
	sigset_t mask;
	size_t mcsize;
	int error;

	/*
	 * The trampoline hands us the context.
	 * It is unsafe to keep track of it ourselves, in the event that a
	 * program jumps out of a signal hander.
	 */
	if ((error = copyin(SCARG(uap, uctx), &uctx, sizeof(uctx))) != 0)
		return (error);

	/* Check mcontext size, as it is handed by user code */
	mcsize = uctx.uc_mcsize;
	if (mcsize > sizeof(mctx))
		mcsize = sizeof(mctx);

	if ((error = copyin(uctx.uc_mcontext, &mctx, mcsize)) != 0)
		return (error);

	/* Check for security abuse */
	tf = trapframe(l);
	if (!PSL_USEROK_P(mctx.ss.srr1)) {
		DPRINTF(("uctx.ss.srr1 = 0x%08x, rf->srr1 = 0x%08lx\n",
		    mctx.ss.srr1, tf->srr1));
		return (EINVAL);
	}

	/* Restore the context */
	tf->dar = mctx.es.dar;
	tf->dsisr = mctx.es.dsisr;
	tf->exc = mctx.es.exception;

	tf->srr0 = mctx.ss.srr0;
	tf->srr1 = mctx.ss.srr1;
	memcpy(&tf->fixreg[0], &mctx.ss.gpreg[0], sizeof(mctx.ss.gpreg));
	tf->cr = mctx.ss.cr;
	tf->xer = mctx.ss.xer;
	tf->lr = mctx.ss.lr;
	tf->ctr = mctx.ss.ctr;

	/* Restore signal stack */
	if (uctx.uc_onstack & SS_ONSTACK)
		l->l_sigstk.ss_flags |= SS_ONSTACK;
	else
		l->l_sigstk.ss_flags &= ~SS_ONSTACK;

	/* Restore signal mask */
	native_sigset13_to_sigset(&uctx.uc_sigmask, &mask);
	(void)sigprocmask1(l, SIG_SETMASK, &mask, 0);

	return (EJUSTRETURN);
}

/*
 * This is the version used starting with X.3 binaries
 */
int
darwin_sys_sigreturn(struct lwp *l, const struct darwin_sys_sigreturn_args *uap, register_t *retval)
{
	/* {
		syscallarg(struct darwin_ucontext *) uctx;
		syscallarg(int) ucvers;
	} */

	switch (SCARG(uap, ucvers)) {
	case DARWIN_UCVERS_X2:
		return darwin_sys_sigreturn_x2(l, (const void *)uap, retval);
		break;

	default:
		printf("darwin_sys_sigreturn: ucvers = %d\n", 
		    SCARG(uap, ucvers));
		break;
	}
	return (EJUSTRETURN);
}

/*
 * Set the return value for darwin binaries after a fork(). The userland
 * libSystem stub expects the child pid to be in retval[0] for the parent
 * and the child as well. It will perform the required operation to transform 
 * it in the POSIXly correct value: zero for the child.
 * We also need to skip the next instruction because the system call
 * was successful (We also do this in the syscall handler, Darwin 
 * works that way).
 */
void
darwin_fork_child_return(void *arg)
{
	struct lwp * const l = arg;
	struct proc * const p = l->l_proc;
	struct trapframe * const tf = trapframe(l);

	child_return(arg);

	tf->fixreg[FIRSTARG] = p->p_pid;
	tf->srr0 +=4;

	return;
}