1  /* Copyright (C) 2001-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  #include <libintl.h>
      19  #include <stdarg.h>
      20  #include <stdio.h>
      21  #include <stdlib.h>
      22  #include <ucontext.h>
      23  
      24  /* This implementation can handle any ARGC value but only
      25     normal integer type parameters. Parameters of type float,
      26     double, complex and structure with sizes 0, 2, 4 or 8
      27     won't work.
      28     makecontext sets up a stack and the registers for the
      29     user context. The stack looks like this:
      30  	   size                         offset
      31      %r15 ->    +-----------------------+
      32  	     4 | back chain (zero)     |  0
      33  	     4 | reserved              |  4
      34  	    88 | save area for (*func) |  8
      35  	       +-----------------------+
      36  	     n | overflow parameters   | 96
      37  	       +-----------------------+
      38     The registers are set up like this:
      39       %r2-%r6: parameters 1 to 5
      40       %r7    : (*func) pointer
      41       %r8    : uc_link from ucontext structure
      42       %r9    : address of setcontext
      43       %r14   : return address to uc_link trampoline
      44       %r15   : stack pointer.
      45  
      46     The trampoline looks like this:
      47       basr  %r14,%r7
      48       lr    %r2,%r8
      49       br    %r9.  */
      50  
      51  void
      52  __makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...)
      53  {
      54    extern void __makecontext_ret (void);
      55    unsigned long int *sp;
      56    va_list ap;
      57  
      58    sp = (unsigned long int *) (((unsigned long int) ucp->uc_stack.ss_sp
      59  			       + ucp->uc_stack.ss_size) & -8L);
      60  
      61    /* Set the return address to trampoline.  */
      62    ucp->uc_mcontext.gregs[14] = (long int) __makecontext_ret;
      63  
      64    /* Set register parameters.  */
      65    va_start (ap, argc);
      66    for (int i = 0; i < argc && i < 5; ++i)
      67      ucp->uc_mcontext.gregs[2 + i] = va_arg (ap, long int);
      68  
      69    /* The remaining arguments go to the overflow area.  */
      70    if (argc > 5)
      71      {
      72        sp -= argc - 5;
      73        for (int i = 5; i < argc; ++i)
      74  	sp[i - 5] = va_arg (ap, long int);
      75      }
      76    va_end (ap);
      77  
      78    /* Make room for the save area and set the backchain.  */
      79    sp -= 24;
      80    *sp = 0;
      81  
      82    /* Pass (*func) to __makecontext_ret in %r7.  */
      83    ucp->uc_mcontext.gregs[7] = (long int) func;
      84  
      85    /* Pass ucp->uc_link to __makecontext_ret in %r8.  */
      86    ucp->uc_mcontext.gregs[8] = (long int) ucp->uc_link;
      87  
      88    /* Pass address of setcontext in %r9.  */
      89    ucp->uc_mcontext.gregs[9] = (long int) &setcontext;
      90  
      91    /* Set stack pointer.  */
      92    ucp->uc_mcontext.gregs[15] = (long int) sp;
      93  }
      94  
      95  weak_alias (__makecontext, makecontext)