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