aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/mach/hurd/powerpc/sigreturn.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/mach/hurd/powerpc/sigreturn.c')
-rw-r--r--sysdeps/mach/hurd/powerpc/sigreturn.c186
1 files changed, 186 insertions, 0 deletions
diff --git a/sysdeps/mach/hurd/powerpc/sigreturn.c b/sysdeps/mach/hurd/powerpc/sigreturn.c
new file mode 100644
index 0000000000..18e37a3d41
--- /dev/null
+++ b/sysdeps/mach/hurd/powerpc/sigreturn.c
@@ -0,0 +1,186 @@
+/* Return from signal handler for Hurd. PowerPC version.
+ Copyright (C) 1996,97,98,2001 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <hurd.h>
+#include <hurd/signal.h>
+#include <hurd/threadvar.h>
+#include <stdlib.h>
+
+int
+__sigreturn (struct sigcontext *scp)
+{
+ struct hurd_sigstate *ss;
+ mach_port_t *reply_port;
+
+ if (scp == NULL || (scp->sc_mask & _SIG_CANT_MASK))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ss = _hurd_self_sigstate ();
+ __spin_lock (&ss->lock);
+
+ /* Restore the set of blocked signals, and the intr_port slot. */
+ ss->blocked = scp->sc_mask;
+ ss->intr_port = scp->sc_intr_port;
+
+ /* Check for pending signals that were blocked by the old set. */
+ if (ss->pending & ~ss->blocked)
+ {
+ /* There are pending signals that just became unblocked. Wake up the
+ signal thread to deliver them. But first, squirrel away SCP where
+ the signal thread will notice it if it runs another handler, and
+ arrange to have us called over again in the new reality. */
+ ss->context = scp;
+ __spin_unlock (&ss->lock);
+ __msg_sig_post (_hurd_msgport, 0, 0, __mach_task_self ());
+ /* If a pending signal was handled, sig_post never returned. */
+ __spin_lock (&ss->lock);
+ ss->context = NULL;
+ }
+
+ if (scp->sc_onstack)
+ {
+ ss->sigaltstack.ss_flags &= ~SS_ONSTACK; /* XXX threadvars */
+ /* XXX cannot unlock until off sigstack */
+ abort ();
+ }
+ else
+ __spin_unlock (&ss->lock);
+
+ /* Destroy the MiG reply port used by the signal handler, and restore the
+ reply port in use by the thread when interrupted. */
+ reply_port =
+ (mach_port_t *) __hurd_threadvar_location (_HURD_THREADVAR_MIG_REPLY);
+ if (*reply_port)
+ {
+ mach_port_t port = *reply_port;
+
+ /* Assigning MACH_PORT_DEAD here tells libc's mig_get_reply_port not to
+ get another reply port, but avoids mig_dealloc_reply_port trying to
+ deallocate it after the receive fails (which it will, because the
+ reply port will be bogus, whether we do this or not). */
+ *reply_port = MACH_PORT_DEAD;
+
+ __mach_port_destroy (__mach_task_self (), port);
+ }
+ *reply_port = scp->sc_reply_port;
+
+ /* Restore FPU state. */
+#define restore_fpr(n) \
+ asm volatile ("lfd " #n ",%0(31)" : : "i" (n * 4))
+
+ asm volatile ("mr 31,%0" : : "r" (scp->sc_fprs));
+
+ /* Restore the floating-point control/status register. */
+ asm volatile ("lfd 0,256(31)");
+ asm volatile ("mtfsf 0xff,0");
+
+ /* Restore floating-point registers. */
+ restore_fpr (0);
+ restore_fpr (1);
+ restore_fpr (2);
+ restore_fpr (3);
+ restore_fpr (4);
+ restore_fpr (5);
+ restore_fpr (6);
+ restore_fpr (7);
+ restore_fpr (8);
+ restore_fpr (9);
+ restore_fpr (10);
+ restore_fpr (11);
+ restore_fpr (12);
+ restore_fpr (13);
+ restore_fpr (14);
+ restore_fpr (15);
+ restore_fpr (16);
+ restore_fpr (17);
+ restore_fpr (18);
+ restore_fpr (19);
+ restore_fpr (20);
+ restore_fpr (21);
+ restore_fpr (22);
+ restore_fpr (23);
+ restore_fpr (24);
+ restore_fpr (25);
+ restore_fpr (26);
+ restore_fpr (27);
+ restore_fpr (28);
+ restore_fpr (29);
+ restore_fpr (30);
+ restore_fpr (31);
+
+ /* Load all the registers from the sigcontext. */
+#define restore_gpr(n) \
+ asm volatile ("lwz " #n ",%0(31)" : : "i" (n * 4))
+
+ asm volatile ("addi 31,31,-188"); /* r31 = scp->gprs */
+
+ /* Restore the special purpose registers. */
+ asm volatile ("lwz 0,128(31); mtcr 0");
+ asm volatile ("lwz 0,132(31); mtxer 0");
+ asm volatile ("lwz 0,136(31); mtlr 0");
+ asm volatile ("lwz 0,-8(31); mtctr 0"); /* XXX this is the PC */
+#if 0
+ asm volatile ("lwz 0,144(31); mtmq %0"); /* PPC601 only */
+#endif
+
+ /* Restore the normal registers. */
+ restore_gpr (0);
+ restore_gpr (1);
+ restore_gpr (2);
+ restore_gpr (3);
+ restore_gpr (4);
+ restore_gpr (5);
+ restore_gpr (6);
+ restore_gpr (7);
+ restore_gpr (8);
+ restore_gpr (9);
+ restore_gpr (10);
+ restore_gpr (11);
+ restore_gpr (12);
+ restore_gpr (13);
+ restore_gpr (14);
+ restore_gpr (15);
+ restore_gpr (16);
+ restore_gpr (17);
+ restore_gpr (18);
+ restore_gpr (19);
+ restore_gpr (20);
+ restore_gpr (21);
+ restore_gpr (22);
+ restore_gpr (23);
+ restore_gpr (24);
+ restore_gpr (25);
+ restore_gpr (26);
+ restore_gpr (27);
+ restore_gpr (28);
+ restore_gpr (29);
+ restore_gpr (30);
+ restore_gpr (31);
+
+ /* Return. */
+ asm volatile ("bctr"); /* XXX CTR is not restored! */
+
+ /* NOTREACHED */
+ return -1;
+}
+
+weak_alias (__sigreturn, sigreturn)