1 /* 2 * Copyright (c) 2001 Daniel M. Eischen <deischen@freebsd.org> 3 * All rights reserved. 4 * Copyright (c) 2007 Matthew Dillon <dillon@backplane.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Neither the name of the author nor the names of its contributors 13 * may be used to endorse or promote products derived from this software 14 * without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD: src/lib/libc/i386/gen/makecontext.c,v 1.5 2004/12/05 21:22:08 deischen Exp $ 29 */ 30 31 #include <sys/cdefs.h> 32 #include <sys/param.h> 33 #include <sys/signal.h> 34 #include <sys/ucontext.h> 35 36 #include <errno.h> 37 #include <stdarg.h> 38 #include <stdlib.h> 39 #include <unistd.h> 40 41 typedef void (*func_t)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t); 42 43 /* Prototypes */ 44 static void makectx_wrapper(ucontext_t *ucp, func_t func, uint64_t *args); 45 46 __weak_reference(_makecontext, makecontext); 47 48 /* 49 * makecontext() associates a stack with a user thread context and sets 50 * up to call the start function when switched to. The start function 51 * returns to _ctx_start which then calls _ctx_done to terminate the 52 * context. 53 */ 54 void 55 _makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...) 56 { 57 va_list ap; 58 uint64_t *stack_top; 59 uint64_t *argp; 60 int i; 61 62 if (ucp == NULL) 63 return; 64 65 /* 66 * Invalidate a context which did not have a stack associated with 67 * it or for which the stack was too small. The stack check is 68 * kinda silly, though, since we have no control over the stack 69 * usage of the code being set up to run. 70 */ 71 if ((ucp->uc_stack.ss_sp == NULL) || 72 (ucp->uc_stack.ss_size < MINSIGSTKSZ)) { 73 ucp->uc_mcontext.mc_len = 0; 74 } 75 if (argc < 0 || argc > NCARGS) 76 ucp->uc_mcontext.mc_len = 0; 77 78 if (ucp->uc_mcontext.mc_len == sizeof(mcontext_t)) { 79 /* 80 */ 81 stack_top = (uint64_t *)(ucp->uc_stack.ss_sp + 82 ucp->uc_stack.ss_size); 83 stack_top = (uint64_t *)((uint64_t)(stack_top) & ~15UL); 84 85 argp = stack_top - 6; 86 stack_top -= 7; 87 88 /* Add all the arguments: */ 89 va_start(ap, argc); 90 for (i = 0; i < argc; i++) { 91 argp[i] = va_arg(ap, uint64_t); 92 } 93 va_end(ap); 94 for(i = argc; i < 6; i++) { 95 argp[i] = 0; 96 } 97 98 /* 99 * Set the machine context to point to the top of the 100 * stack and the program counter to the context start 101 * wrapper. Note that setcontext() pushes the return 102 * address onto the top of the stack, so allow for this 103 * by adjusting the stack downward 1 slot. Also set 104 * %rbp to point to the base of the stack where ucp 105 * is stored. 106 */ 107 ucp->uc_mcontext.mc_rdi = (register_t)ucp; 108 ucp->uc_mcontext.mc_rsi = (register_t)start; 109 ucp->uc_mcontext.mc_rdx = (register_t)argp; 110 ucp->uc_mcontext.mc_rbp = 0; 111 ucp->uc_mcontext.mc_rbx = (register_t)stack_top; 112 ucp->uc_mcontext.mc_rsp = (register_t)stack_top; 113 ucp->uc_mcontext.mc_rip = (register_t)makectx_wrapper; 114 } 115 } 116 117 /* */ 118 static void 119 makectx_wrapper(ucontext_t *ucp, func_t func, uint64_t *args) 120 { 121 (*func)(args[0], args[1], args[2], args[3], args[4], args[5]); 122 if(ucp->uc_link == NULL) 123 exit(0); 124 125 setcontext((const ucontext_t *)ucp->uc_link); 126 127 /* should never reach this */ 128 abort(); 129 } 130