1 /* Create new context.
2    Copyright (C) 2015-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 /* makecontext sets up a stack and the registers for the
25    user context.  The stack looks like this:
26 
27                +-----------------------+
28 	       | padding as required   |
29                +-----------------------+
30     sp ->      | parameters 5 to n     |
31                +-----------------------+
32 
33    The registers are set up like this:
34      r4--r7 : parameter 1 to 4
35      r16    : uc_link
36      sp     : stack pointer.
37 */
38 
39 void
__makecontext(ucontext_t * ucp,void (* func)(void),int argc,...)40 __makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...)
41 {
42   extern void __startcontext (void);
43   unsigned long *sp;
44   va_list ap;
45   int i;
46 
47   sp = (unsigned long *)
48     ((uintptr_t) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
49 
50   /* Allocate stack arguments.  */
51   sp -= argc < 4 ? 0 : argc - 4;
52 
53   /* Keep the stack aligned.  */
54   sp = (unsigned long*) (((uintptr_t) sp) & -4L);
55 
56   /* Init version field.  */
57   ucp->uc_mcontext.version = 2;
58   /* Keep uc_link in r16.  */
59   ucp->uc_mcontext.regs[15] = (uintptr_t) ucp->uc_link;
60   /* Return address points to __startcontext().  */
61   ucp->uc_mcontext.regs[23] = (uintptr_t) &__startcontext;
62   /* Frame pointer is null.  */
63   ucp->uc_mcontext.regs[24] = (uintptr_t) 0;
64   /* Restart in user-space starting at 'func'.  */
65   ucp->uc_mcontext.regs[27] = (uintptr_t) func;
66   /* Set stack pointer.  */
67   ucp->uc_mcontext.regs[28] = (uintptr_t) sp;
68 
69   va_start (ap, argc);
70   for (i = 0; i < argc; ++i)
71     if (i < 4)
72       ucp->uc_mcontext.regs[i + 3] = va_arg (ap, unsigned long);
73     else
74       sp[i - 4] = va_arg (ap, unsigned long);
75 
76   va_end (ap);
77 }
78 
79 weak_alias (__makecontext, makecontext)
80