Back to index

glibc  2.9
sigreturn.c
Go to the documentation of this file.
00001 /* Return from signal handler in GNU C library for Hurd.  Alpha version.
00002    Copyright (C) 1994,95,97,98,2002 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <hurd.h>
00021 #include <hurd/signal.h>
00022 #include <hurd/threadvar.h>
00023 #include <hurd/msg.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 
00027 int
00028 __sigreturn (struct sigcontext *scp)
00029 {
00030   struct hurd_sigstate *ss;
00031   mach_port_t *reply_port;
00032 
00033   if (scp == NULL || (scp->sc_mask & _SIG_CANT_MASK))
00034     {
00035       errno = EINVAL;
00036       return -1;
00037     }
00038 
00039   ss = _hurd_self_sigstate ();
00040   __spin_lock (&ss->lock);
00041 
00042   /* Restore the set of blocked signals, and the intr_port slot.  */
00043   ss->blocked = scp->sc_mask;
00044   ss->intr_port = scp->sc_intr_port;
00045 
00046   /* Check for pending signals that were blocked by the old set.  */
00047   if (ss->pending & ~ss->blocked)
00048     {
00049       /* There are pending signals that just became unblocked.  Wake up the
00050         signal thread to deliver them.  But first, squirrel away SCP where
00051         the signal thread will notice it if it runs another handler, and
00052         arrange to have us called over again in the new reality.  */
00053       ss->context = scp;
00054       /* Clear the intr_port slot, since we are not in fact doing
00055         an interruptible RPC right now.  If SS->intr_port is not null,
00056         the SCP context is doing an interruptible RPC, but the signal
00057         thread will examine us while we are blocked in the sig_post RPC.  */
00058       ss->intr_port = MACH_PORT_NULL;
00059       __spin_unlock (&ss->lock);
00060       __msg_sig_post (_hurd_msgport, 0, 0, __mach_task_self ());
00061       /* If a pending signal was handled, sig_post never returned.  */
00062       __spin_lock (&ss->lock);
00063     }
00064 
00065   if (scp->sc_onstack)
00066     {
00067       ss->sigaltstack.ss_flags &= ~SS_ONSTACK; /* XXX threadvars */
00068       /* XXX cannot unlock until off sigstack */
00069       abort ();
00070     }
00071   else
00072     __spin_unlock (&ss->lock);
00073 
00074   /* Destroy the MiG reply port used by the signal handler, and restore the
00075      reply port in use by the thread when interrupted.  */
00076   reply_port =
00077     (mach_port_t *) __hurd_threadvar_location (_HURD_THREADVAR_MIG_REPLY);
00078   if (*reply_port)
00079     __mach_port_destroy (__mach_task_self (), *reply_port);
00080   *reply_port = scp->sc_reply_port;
00081 
00082   if (scp->sc_used_fpa)
00083     {
00084       /* Restore FPU state.  */
00085 
00086       /* Restore the floating-point control/status register.
00087         We must do this first because the compiler will need
00088         a temporary FP register for the load.  */
00089       asm volatile ("mt_fpcr %0" : : "f" (scp->sc_fpcsr));
00090 
00091       /* Restore floating-point registers. */
00092 #define restore_fpr(n) \
00093   asm volatile ("ldt $f" #n ",%0" : : "m" (scp->sc_fpregs[n]))
00094       restore_fpr (0);
00095       restore_fpr (1);
00096       restore_fpr (2);
00097       restore_fpr (3);
00098       restore_fpr (4);
00099       restore_fpr (5);
00100       restore_fpr (6);
00101       restore_fpr (7);
00102       restore_fpr (8);
00103       restore_fpr (9);
00104       restore_fpr (10);
00105       restore_fpr (11);
00106       restore_fpr (12);
00107       restore_fpr (13);
00108       restore_fpr (14);
00109       restore_fpr (15);
00110       restore_fpr (16);
00111       restore_fpr (17);
00112       restore_fpr (18);
00113       restore_fpr (19);
00114       restore_fpr (20);
00115       restore_fpr (21);
00116       restore_fpr (22);
00117       restore_fpr (23);
00118       restore_fpr (24);
00119       restore_fpr (25);
00120       restore_fpr (26);
00121       restore_fpr (27);
00122       restore_fpr (28);
00123       restore_fpr (29);
00124       restore_fpr (30);
00125     }
00126 
00127   /* Load all the registers from the sigcontext.  */
00128 #define restore_gpr(n) \
00129   asm volatile ("ldq $" #n ",%0" : : "m" (scpreg->sc_regs[n]))
00130 
00131   {
00132     /* The `rei' PAL pseudo-instruction restores registers $2..$7, the PC
00133        and processor status.  So we can use these few registers for our
00134        working variables.  Unfortunately, it finds its data on the stack
00135        and merely pops the SP ($30) over the words of state restored,
00136        allowing no other option for the new SP value.  So we must push the
00137        registers and PSW it will to restore, onto the user's stack and let
00138        it pop them from there.  */
00139     register const struct sigcontext *const scpreg asm ("$2") = scp;
00140     register integer_t *usp asm ("$3") = (integer_t *) scpreg->sc_regs[30];
00141     register integer_t usp_align asm ("$4");
00142 
00143     /* Push an 8-word "trap frame" onto the user stack for `rei':
00144        registers $2..$7, the PC, and the PSW.  */
00145 
00146     register struct rei_frame
00147       {
00148        integer_t regs[5], pc, ps;
00149       } *rei_frame asm ("$5");
00150 
00151     usp -= 8;
00152     /* `rei' demands that the stack be aligned to a 64 byte (8 word)
00153        boundary; bits 61..56 of the PSW are OR'd back into the SP value
00154        after popping the 8-word trap frame, so we store (sp % 64)
00155        there and this restores the original user SP.  */
00156     usp_align = (integer_t) usp & 63L;
00157     rei_frame = (void *) ((integer_t) usp & ~63L);
00158 
00159     /* Copy the registers and PC from the sigcontext.  */
00160     memcpy (rei_frame->regs, &scpreg->sc_regs[2], sizeof rei_frame->regs);
00161     rei_frame->pc = scpreg->sc_pc;
00162 
00163     /* Compute the new PS value to be restored.  `rei' adds the value at
00164        bits 61..56 to the SP to compensate for the alignment above that
00165        cleared the low 6 bits; bits 5..3 are the new mode/privilege level
00166        (must be >= current mode; 3 == user mode); bits 2..0 are "software",
00167        unused by the processor or kernel (XXX should trampoline save these?
00168        How?); in user mode, `rei' demands that all other bits be zero.  */
00169     rei_frame->ps = (usp_align << 56) | (3 << 3); /* XXX low 3 bits??? */
00170 
00171     /* Restore the other general registers: everything except $2..$7, which
00172        are in the `rei' trap frame we set up above, and $30, which is the
00173        SP which is popped by `rei'.  */
00174     restore_gpr (1);
00175     restore_gpr (8);
00176     restore_gpr (9);
00177     restore_gpr (10);
00178     restore_gpr (11);
00179     restore_gpr (12);
00180     restore_gpr (13);
00181     restore_gpr (14);
00182     restore_gpr (15);
00183     restore_gpr (16);
00184     restore_gpr (17);
00185     restore_gpr (18);
00186     restore_gpr (19);
00187     restore_gpr (20);
00188     restore_gpr (21);
00189     restore_gpr (22);
00190     restore_gpr (23);
00191     restore_gpr (24);
00192     restore_gpr (25);
00193     restore_gpr (26);
00194     restore_gpr (27);
00195     restore_gpr (28);
00196     restore_gpr (29);
00197 
00198     /* Switch the stack pointer to the trap frame set up on
00199        the user stack and do the magical `rei' PAL call.  */
00200     asm volatile ("mov %0, $30\n"
00201                 "call_pal %1"
00202                 : : "r" (rei_frame), "i" (63)); /* PAL_rti */
00203     /* Firewall.  */
00204     asm volatile ("halt");
00205   }
00206 
00207   /* NOTREACHED */
00208   return -1;
00209 }
00210 
00211 weak_alias (__sigreturn, sigreturn)