(root)/
glibc-2.38/
sysdeps/
mach/
hurd/
i386/
sigreturn.c
       1  /* Copyright (C) 1991-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  register int *sp asm ("%esp");
      19  
      20  #include <hurd.h>
      21  #include <hurd/signal.h>
      22  #include <hurd/msg.h>
      23  #include <stdlib.h>
      24  #include <string.h>
      25  
      26  /* This is run on the thread stack after restoring it, to be able to
      27     unlock SS off sigstack.  */
      28  static void
      29  __sigreturn2 (int *usp, struct sigcontext *scp)
      30  {
      31    mach_port_t reply_port;
      32    struct hurd_sigstate *ss;
      33  
      34    /* We know the sigstate must be initialized by the call below, but the
      35       compiler does not.  Help it out a little bit by eliding the check that
      36       _hurd_self_sigstate makes otherwise.  */
      37    ss = THREAD_GETMEM (THREAD_SELF, _hurd_sigstate);
      38    _hurd_sigstate_unlock (ss);
      39  
      40    /* Destroy the MiG reply port used by the signal handler, and restore the
      41       reply port in use by the thread when interrupted.
      42  
      43       We cannot use the original reply port for our RPCs that we do here, since
      44       we could unexpectedly receive/consume a reply message meant for the user
      45       (in particular, msg_sig_post_reply), and also since we would deallocate
      46       the port if *our* RPC fails, which we don't want to do since the user
      47       still has the old name.  And so, temporarily set MACH_PORT_DEAD as our
      48       reply name, and make sure destroying the port is the very last RPC we
      49       do.  */
      50    reply_port = THREAD_GETMEM (THREAD_SELF, reply_port);
      51    THREAD_SETMEM (THREAD_SELF, reply_port, MACH_PORT_DEAD);
      52    if (__glibc_likely (MACH_PORT_VALID (reply_port)))
      53      (void) __mach_port_mod_refs (__mach_task_self (), reply_port,
      54                                   MACH_PORT_RIGHT_RECEIVE, -1);
      55    THREAD_SETMEM (THREAD_SELF, reply_port, scp->sc_reply_port);
      56  
      57    sp = usp;
      58  #define A(line) asm volatile (#line)
      59    /* The members in the sigcontext are arranged in this order
      60       so we can pop them easily.  */
      61  
      62    /* Pop the segment registers (except %cs and %ss, done last).  */
      63    A (popl %gs);
      64    A (popl %fs);
      65    A (popl %es);
      66    A (popl %ds);
      67    /* Pop the general registers.  */
      68    A (popa);
      69    /* Pop the processor flags.  */
      70    A (popf);
      71    /* Return to the saved PC.  */
      72    A (ret);
      73  
      74    /* Firewall.  */
      75    A (hlt);
      76  #undef A
      77    __builtin_unreachable ();
      78  }
      79  
      80  int
      81  __sigreturn (struct sigcontext *scp)
      82  {
      83    struct hurd_sigstate *ss;
      84    struct hurd_userlink *link = (void *) &scp[1];
      85  
      86    if (__glibc_unlikely (scp == NULL || (scp->sc_mask & _SIG_CANT_MASK)))
      87      return __hurd_fail (EINVAL);
      88  
      89    ss = _hurd_self_sigstate ();
      90    _hurd_sigstate_lock (ss);
      91  
      92    /* Remove the link on the `active resources' chain added by
      93       _hurd_setup_sighandler.  Its purpose was to make sure
      94       that we got called; now we have, it is done.  */
      95    _hurd_userlink_unlink (link);
      96  
      97    /* Restore the set of blocked signals, and the intr_port slot.  */
      98    ss->blocked = scp->sc_mask;
      99    ss->intr_port = scp->sc_intr_port;
     100  
     101    /* Check for pending signals that were blocked by the old set.  */
     102    if (_hurd_sigstate_pending (ss) & ~ss->blocked)
     103      {
     104        /* There are pending signals that just became unblocked.  Wake up the
     105  	 signal thread to deliver them.  But first, squirrel away SCP where
     106  	 the signal thread will notice it if it runs another handler, and
     107  	 arrange to have us called over again in the new reality.  */
     108        ss->context = scp;
     109        _hurd_sigstate_unlock (ss);
     110        __msg_sig_post (_hurd_msgport, 0, 0, __mach_task_self ());
     111        /* If a pending signal was handled, sig_post never returned.
     112  	 If it did return, the pending signal didn't run a handler;
     113  	 proceed as usual.  */
     114        _hurd_sigstate_lock (ss);
     115        ss->context = NULL;
     116      }
     117  
     118    if (scp->sc_onstack)
     119      ss->sigaltstack.ss_flags &= ~SS_ONSTACK;
     120  
     121    if (scp->sc_fpused)
     122      /* Restore the FPU state.  Mach conveniently stores the state
     123         in the format the i387 `frstor' instruction uses to restore it.  */
     124      asm volatile ("frstor %0" : : "m" (scp->sc_fpsave));
     125  
     126    {
     127      /* There are convenient instructions to pop state off the stack, so we
     128         copy the registers onto the user's stack, switch there, pop and
     129         return.  */
     130  
     131      int usp_arg, *usp = (int *) scp->sc_uesp;
     132  
     133      *--usp = scp->sc_eip;
     134      *--usp = scp->sc_efl;
     135      memcpy (usp -= 12, &scp->sc_i386_thread_state, 12 * sizeof (int));
     136      usp_arg = (int) usp;
     137  
     138      *--usp = (int) scp;
     139      /* Pass usp to __sigreturn2 so it can unwind itself easily.  */
     140      *--usp = usp_arg;
     141      /* Bogus return address for __sigreturn2 */
     142      *--usp = 0;
     143      *--usp = (int) __sigreturn2;
     144  
     145      /* Restore thread stack */
     146      sp = usp;
     147      /* Return into __sigreturn2.  */
     148      asm volatile ("ret");
     149      /* Firewall.  */
     150      asm volatile ("hlt");
     151    }
     152  
     153    /* NOTREACHED */
     154    return -1;
     155  }
     156  
     157  weak_alias (__sigreturn, sigreturn)