| /* Create new context. |
| Copyright (C) 2008 Free Software Foundation, Inc. |
| This file is part of the GNU C Library. |
| Contributed by David S. Miller <davem@davemloft.net>, 2008. |
| |
| The GNU C Library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Lesser General Public |
| License as published by the Free Software Foundation; either |
| version 2.1 of the License, or (at your option) any later version. |
| |
| The GNU C Library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public |
| License along with the GNU C Library; if not, write to the Free |
| Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 02111-1307 USA. */ |
| |
| #include <sysdep.h> |
| #include <stdarg.h> |
| #include <stdint.h> |
| #include <ucontext.h> |
| |
| /* Sets up the outgoing arguments and the program counter for a user |
| context for the requested function call. |
| |
| Returning to the correct parent context is pretty simple on |
| Sparc. We only need to link up the register windows correctly. |
| Since global registers are clobbered by calls, we need not be |
| concernred about those, and thus is all could be worked out without |
| using a trampoline. |
| |
| Except that we must deal with the signal mask, thus a trampoline |
| is unavoidable. 32-bit stackframe layout: |
| +-----------------------------------------+ |
| | 7th and further parameters | |
| +-----------------------------------------+ |
| | backup storage for initial 6 parameters | |
| +-----------------------------------------+ |
| | struct return pointer | |
| +-----------------------------------------+ |
| | 8 incoming registers | |
| +-----------------------------------------+ |
| | 8 local registers | |
| %sp --> +-----------------------------------------+ |
| |
| */ |
| |
| void |
| __makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...) |
| { |
| extern void __start_context (void); |
| unsigned long int *sp; |
| va_list ap; |
| int i; |
| |
| sp = (unsigned long int *) (ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size); |
| sp -= 16 + 7 + argc; |
| sp = (unsigned long int *) (((uintptr_t) sp) & ~(8 - 1)); |
| |
| for (i = 0; i < 8; i++) |
| sp[i + 8] = ucp->uc_mcontext.gregs[REG_O0 + i]; |
| |
| /* The struct return pointer is essentially unused, so we can |
| place the link there. */ |
| sp[16] = (unsigned long int) ucp->uc_link; |
| |
| va_start (ap, argc); |
| |
| /* Fill in outgoing arguments, including those which will |
| end up being passed on the stack. */ |
| for (i = 0; i < argc; i++) |
| { |
| unsigned long int arg = va_arg (ap, unsigned long int); |
| if (i < 6) |
| ucp->uc_mcontext.gregs[REG_O0 + i] = arg; |
| else |
| sp[i + 23 - 6] = arg; |
| } |
| |
| va_end (ap); |
| |
| ucp->uc_mcontext.gregs[REG_O6] = (unsigned long int) sp; |
| |
| ucp->uc_mcontext.gregs[REG_O7] = ((unsigned long int) __start_context) - 8; |
| |
| ucp->uc_mcontext.gregs[REG_PC] = (unsigned long int) func; |
| ucp->uc_mcontext.gregs[REG_nPC] = ucp->uc_mcontext.gregs[REG_PC] + 4; |
| } |
| |
| weak_alias (__makecontext, makecontext) |