Back to index

glibc  2.9
trampoline.c
Go to the documentation of this file.
00001 /* Set thread_state for sighandler, and sigcontext to recover.  For PowerPC.
00002    Copyright (C) 1994,1995,1996,1997,1998,1999,2001,2005
00003        Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <hurd/signal.h>
00022 #include <hurd/userlink.h>
00023 #include <thread_state.h>
00024 #include <assert.h>
00025 #include <errno.h>
00026 #include "hurdfault.h"
00027 #include <intr-msg.h>
00028 
00029 struct sigcontext *
00030 _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
00031                      int signo, struct hurd_signal_detail *detail,
00032                      volatile int rpc_wait,
00033                      struct machine_thread_all_state *state)
00034 {
00035   void trampoline (void);
00036   void rpc_wait_trampoline (void);
00037   void *volatile sigsp;
00038   struct sigcontext *scp;
00039 
00040   if (ss->context)
00041     {
00042       /* We have a previous sigcontext that sigreturn was about
00043         to restore when another signal arrived.  We will just base
00044         our setup on that.  */
00045       if (! _hurdsig_catch_memory_fault (ss->context))
00046        {
00047          memcpy (&state->basic, &ss->context->sc_ppc_thread_state,
00048                 sizeof (state->basic));
00049          memcpy (&state->exc, &ss->context->sc_ppc_exc_state,
00050                 sizeof (state->exc));
00051          memcpy (&state->fpu, &ss->context->sc_ppc_float_state,
00052                 sizeof (state->fpu));
00053          state->set = (1 << PPC_THREAD_STATE) | (1 << PPC_EXCEPTION_STATE)
00054            | (1 << PPC_FLOAT_STATE);
00055        }
00056     }
00057 
00058   if (! machine_get_basic_state (ss->thread, state))
00059     return NULL;
00060 
00061   if ((ss->actions[signo].sa_flags & SA_ONSTACK) &&
00062       !(ss->sigaltstack.ss_flags & (SS_DISABLE|SS_ONSTACK)))
00063     {
00064       sigsp = ss->sigaltstack.ss_sp + ss->sigaltstack.ss_size;
00065       ss->sigaltstack.ss_flags |= SS_ONSTACK;
00066       /* XXX need to set up base of new stack for
00067         per-thread variables, cthreads.  */
00068     }
00069   else
00070     sigsp = (char *) state->basic.SP;
00071 
00072   /* Set up the sigcontext structure on the stack.  This is all the stack
00073      needs, since the args are passed in registers (below).  */
00074   sigsp -= sizeof (*scp);
00075   scp = sigsp;
00076   sigsp -= 16;  /* Reserve some space for a stack frame.  */
00077 
00078   if (_hurdsig_catch_memory_fault (scp))
00079     {
00080       /* We got a fault trying to write the stack frame.
00081         We cannot set up the signal handler.
00082         Returning NULL tells our caller, who will nuke us with a SIGILL.  */
00083       return NULL;
00084     }
00085   else
00086     {
00087       int ok;
00088 
00089       /* Set up the sigcontext from the current state of the thread.  */
00090 
00091       scp->sc_onstack = ss->sigaltstack.ss_flags & SS_ONSTACK ? 1 : 0;
00092 
00093       /* struct sigcontext is laid out so that starting at sc_srr0
00094         mimics a struct ppc_thread_state.  */
00095       memcpy (&scp->sc_ppc_thread_state,
00096              &state->basic, sizeof (state->basic));
00097 
00098       /* struct sigcontext is laid out so that starting at sc_dar
00099         mimics a struct ppc_exc_state.  */
00100       ok = machine_get_state (ss->thread, state, PPC_EXCEPTION_STATE,
00101                             &state->exc, &scp->sc_ppc_exc_state,
00102                             sizeof (state->exc));
00103 
00104       /* struct sigcontext is laid out so that starting at sc_fprs[0]
00105         mimics a struct ppc_float_state.  */
00106       if (ok)
00107        ok = machine_get_state (ss->thread, state, PPC_FLOAT_STATE,
00108                             &state->fpu, &scp->sc_ppc_float_state,
00109                             sizeof (state->fpu));
00110 
00111       _hurdsig_end_catch_fault ();
00112 
00113       if (!ok)
00114        return NULL;
00115     }
00116 
00117   /* Modify the thread state to call the trampoline code on the new stack.  */
00118   if (rpc_wait)
00119     {
00120       /* The signalee thread was blocked in a mach_msg_trap system call,
00121         still waiting for a reply.  We will have it run the special
00122         trampoline code which retries the message receive before running
00123         the signal handler.
00124 
00125         To do this we change the OPTION argument in its registers to
00126         enable only message reception, since the request message has
00127         already been sent.  */
00128 
00129       /* The system call arguments are stored in consecutive registers
00130         starting with r3.  */
00131       struct mach_msg_trap_args *args = (void *) &state->basic.r3;
00132 
00133       if (_hurdsig_catch_memory_fault (args))
00134        {
00135          /* Faulted accessing ARGS.  Bomb.  */
00136          return NULL;
00137        }
00138 
00139       assert (args->option & MACH_RCV_MSG);
00140       /* Disable the message-send, since it has already completed.  The
00141         calls we retry need only wait to receive the reply message.  */
00142       args->option &= ~MACH_SEND_MSG;
00143 
00144       /* Limit the time to receive the reply message, in case the server
00145         claimed that `interrupt_operation' succeeded but in fact the RPC
00146         is hung.  */
00147       args->option |= MACH_RCV_TIMEOUT;
00148       args->timeout = _hurd_interrupted_rpc_timeout;
00149 
00150       _hurdsig_end_catch_fault ();
00151 
00152       state->basic.PC = (int) rpc_wait_trampoline;
00153       /* After doing the message receive, the trampoline code will need to
00154         update the r3 value to be restored by sigreturn.  To simplify
00155         the assembly code, we pass the address of its slot in SCP to the
00156         trampoline code in r10.  */
00157       state->basic.r10 = (long int) &scp->sc_gprs[3];
00158       /* We must preserve the mach_msg_trap args in r3..r9.
00159         Pass the handler args to the trampoline code in r11..r13.  */
00160       state->basic.r11 = signo;
00161       state->basic.r12 = detail->code;
00162       state->basic.r13 = (int) scp;
00163     }
00164   else
00165     {
00166       state->basic.PC = (int) trampoline;
00167       state->basic.r3 = signo;
00168       state->basic.r4 = detail->code;
00169       state->basic.r5 = (int) scp;
00170     }
00171 
00172   state->basic.r1 = (int) sigsp;  /* r1 is the stack pointer.  */
00173 
00174   /* We pass the handler function to the trampoline code in ctr.  */
00175   state->basic.ctr = (int) handler;
00176   /* In r15, we store the address of __sigreturn itself,
00177      for the trampoline code to use.  */
00178   state->basic.r15 = (int) &__sigreturn;
00179   /* In r16, we save the SCP value to pass to __sigreturn
00180      after the handler returns.  */
00181   state->basic.r16 = (int) scp;
00182 
00183   /* In r3, we store a pointer to the registers in STATE so that the
00184      trampoline code can load the registers from that.  For some reason,
00185      thread_set_state doesn't set all registers.  */
00186   state->basic.r17 = state->basic.r3;  /* Store the real r3 in r17.  */
00187   state->basic.r3 = (int) &state->basic.r0;
00188 
00189   return scp;
00190 }
00191 
00192 /* The trampoline code follows.  This used to be located inside
00193    _hurd_setup_sighandler, but was optimized away by gcc 2.95.  */
00194 
00195 /* This function sets some registers which the trampoline code uses
00196    and which are not automatically set by thread_set_state.
00197    In r3 we have a pointer to the registers in STATE.  */
00198 asm ("trampoline_load_registers:\n"
00199      "lwz 17,68(3)\n"  /* The real r3.  */
00200      "lwz 4,16(3)\n"
00201      "lwz 5,20(3)\n"
00202      "lwz 6,24(3)\n"
00203      "lwz 7,28(3)\n"
00204      "lwz 8,32(3)\n"
00205      "lwz 9,36(3)\n"
00206      "lwz 10,40(3)\n"
00207      "lwz 11,44(3)\n"
00208      "lwz 12,48(3)\n"
00209      "lwz 13,52(3)\n"
00210      "lwz 14,56(3)\n"
00211      "lwz 15,60(3)\n"
00212      "lwz 16,64(3)\n"
00213      "mr 3,17\n"
00214      "blr\n");
00215 
00216 asm ("rpc_wait_trampoline:\n");
00217   /* This is the entry point when we have an RPC reply message to receive
00218      before running the handler.  The MACH_MSG_SEND bit has already been
00219      cleared in the OPTION argument in our registers.  For our convenience,
00220      r10 points to the sc_regs[3] member of the sigcontext (saved r3).  */
00221 
00222 asm (/* Retry the interrupted mach_msg system call.  */
00223      "bl trampoline_load_registers\n"
00224      "li 0, -25\n"          /* mach_msg_trap */
00225      "sc\n"
00226      /* When the sigcontext was saved, r3 was MACH_RCV_INTERRUPTED.  But
00227        now the message receive has completed and the original caller of
00228        the RPC (i.e. the code running when the signal arrived) needs to
00229        see the final return value of the message receive in r3.  So
00230        store the new r3 value into the sc_regs[3] member of the sigcontext
00231        (whose address is in r10 to make this code simpler).  */
00232      "stw 3, 0(10)\n"
00233      /* Since the argument registers needed to have the mach_msg_trap
00234        arguments, we've stored the arguments to the handler function
00235        in registers r11..r13 of the state structure.  */
00236      "mr 3,11\n"
00237      "mr 4,12\n"
00238      "mr 5,13\n");
00239 
00240 asm ("trampoline:\n");
00241   /* Entry point for running the handler normally.  The arguments to the
00242      handler function are already in the standard registers:
00243 
00244        r3     SIGNO
00245        r4     SIGCODE
00246        r5     SCP
00247 
00248      r16 also contains SCP; this value is callee-saved (and so should not get
00249      clobbered by running the handler).  We use this saved value to pass to
00250      __sigreturn, so the handler can clobber the argument registers if it
00251      likes.  */
00252 asm ("bl trampoline_load_registers\n"
00253      "bctrl\n"              /* Call the handler function.  */
00254      "mtctr 15\n"    /* Copy &__sigreturn to CTR.  */
00255      "mr 3,16\n"     /* Copy the saved SCP to r3.  */
00256      "bctr\n"        /* Call __sigreturn (SCP).  */
00257      );