1 | /* Copyright (C) 2001-2024 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 | 8 | back chain (zero) | 0 |
33 | 8 | reserved | 8 |
34 | 144 | save area for (*func) | 16 |
35 | +-----------------------+ |
36 | n | overflow parameters | 160 |
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 | lgr %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 | /* Store psw mask to 0x0 and addr to trampoline. Then the address |
64 | can be retrieved from the ucontext structure in the same way as if it |
65 | is created by kernel and passed to a signal-handler. */ |
66 | ucp->uc_mcontext.psw.addr = (long int) __makecontext_ret; |
67 | ucp->uc_mcontext.psw.mask = 0; |
68 | |
69 | /* Set register parameters. */ |
70 | va_start (ap, argc); |
71 | for (int i = 0; i < argc && i < 5; ++i) |
72 | ucp->uc_mcontext.gregs[2 + i] = va_arg (ap, long int); |
73 | |
74 | /* The remaining arguments go to the overflow area. */ |
75 | if (argc > 5) |
76 | { |
77 | sp -= argc - 5; |
78 | for (int i = 5; i < argc; ++i) |
79 | sp[i - 5] = va_arg (ap, long int); |
80 | } |
81 | va_end (ap); |
82 | |
83 | /* Make room for the save area and set the backchain. */ |
84 | sp -= 20; |
85 | *sp = 0; |
86 | |
87 | /* Pass (*func) to __makecontext_ret in %r7. */ |
88 | ucp->uc_mcontext.gregs[7] = (long int) func; |
89 | |
90 | /* Pass ucp->uc_link to __makecontext_ret in %r8. */ |
91 | ucp->uc_mcontext.gregs[8] = (long int) ucp->uc_link; |
92 | |
93 | /* Pass address of setcontext in %r9. */ |
94 | ucp->uc_mcontext.gregs[9] = (long int) &setcontext; |
95 | |
96 | /* Set stack pointer. */ |
97 | ucp->uc_mcontext.gregs[15] = (long int) sp; |
98 | } |
99 | |
100 | weak_alias (__makecontext, makecontext) |
101 | |