1 | /* Create new context. |
2 | Copyright (C) 2008-2022 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <sysdep.h> |
20 | #include <stdarg.h> |
21 | #include <stdint.h> |
22 | #include <ucontext.h> |
23 | |
24 | /* Sets up the outgoing arguments and the program counter for a user |
25 | context for the requested function call. |
26 | |
27 | Returning to the correct parent context is pretty simple on |
28 | Sparc. We only need to link up the register windows correctly. |
29 | Since global registers are clobbered by calls, we need not be |
30 | concerned about those, and thus is all could be worked out without |
31 | using a trampoline. |
32 | |
33 | Except that we must deal with the signal mask, thus a trampoline |
34 | is unavoidable. 32-bit stackframe layout: |
35 | +-----------------------------------------+ |
36 | | 7th and further parameters | |
37 | +-----------------------------------------+ |
38 | | backup storage for initial 6 parameters | |
39 | +-----------------------------------------+ |
40 | | struct return pointer | |
41 | +-----------------------------------------+ |
42 | | 8 incoming registers | |
43 | +-----------------------------------------+ |
44 | | 8 local registers | |
45 | %sp --> +-----------------------------------------+ |
46 | |
47 | */ |
48 | |
49 | void |
50 | __makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...) |
51 | { |
52 | extern void __start_context (void); |
53 | unsigned long int *sp; |
54 | va_list ap; |
55 | int i; |
56 | |
57 | sp = (unsigned long int *) (ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size); |
58 | sp -= 16 + 7 + argc; |
59 | sp = (unsigned long int *) (((uintptr_t) sp) & ~(8 - 1)); |
60 | |
61 | for (i = 0; i < 8; i++) |
62 | sp[i + 8] = ucp->uc_mcontext.gregs[REG_O0 + i]; |
63 | |
64 | /* The struct return pointer is essentially unused, so we can |
65 | place the link there. */ |
66 | sp[16] = (unsigned long int) ucp->uc_link; |
67 | |
68 | va_start (ap, argc); |
69 | |
70 | /* Fill in outgoing arguments, including those which will |
71 | end up being passed on the stack. */ |
72 | for (i = 0; i < argc; i++) |
73 | { |
74 | unsigned long int arg = va_arg (ap, unsigned long int); |
75 | if (i < 6) |
76 | ucp->uc_mcontext.gregs[REG_O0 + i] = arg; |
77 | else |
78 | sp[i + 23 - 6] = arg; |
79 | } |
80 | |
81 | va_end (ap); |
82 | |
83 | ucp->uc_mcontext.gregs[REG_O6] = (unsigned long int) sp; |
84 | |
85 | ucp->uc_mcontext.gregs[REG_O7] = ((unsigned long int) __start_context) - 8; |
86 | |
87 | ucp->uc_mcontext.gregs[REG_PC] = (unsigned long int) func; |
88 | ucp->uc_mcontext.gregs[REG_nPC] = ucp->uc_mcontext.gregs[REG_PC] + 4; |
89 | } |
90 | |
91 | weak_alias (__makecontext, makecontext) |
92 | |