1 /* Copyright (C) 2001-2022 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
__makecontext(ucontext_t * ucp,void (* func)(void),int argc,...)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)
96