1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2003 Marcel Moolenaar 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 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/types.h> 33 #include <sys/ucontext.h> 34 #include <stdarg.h> 35 #include <stdlib.h> 36 37 typedef void (*func_t)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, 38 uint64_t); 39 40 /* Prototypes */ 41 static void makectx_wrapper(ucontext_t *ucp, func_t func, uint64_t *args); 42 43 __weak_reference(__makecontext, makecontext); 44 45 void 46 __makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...) 47 { 48 uint64_t *args; 49 uint64_t *sp; 50 va_list ap; 51 int i; 52 53 /* A valid context is required. */ 54 if ((ucp == NULL) || (ucp->uc_mcontext.mc_len != sizeof(mcontext_t))) 55 return; 56 else if ((argc < 0) || (argc > 6) || (ucp->uc_stack.ss_sp == NULL) || 57 (ucp->uc_stack.ss_size < MINSIGSTKSZ)) { 58 /* 59 * This should really return -1 with errno set to ENOMEM 60 * or something, but the spec says that makecontext is 61 * a void function. At least make sure that the context 62 * isn't valid so it can't be used without an error. 63 */ 64 ucp->uc_mcontext.mc_len = 0; 65 return; 66 } 67 68 /* Align the stack to 16 bytes. */ 69 sp = (uint64_t *)(ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size); 70 sp = (uint64_t *)((uint64_t)sp & ~15UL); 71 72 /* Allocate space for a maximum of 6 arguments on the stack. */ 73 args = sp - 6; 74 75 /* 76 * Account for arguments on stack and do the funky C entry alignment. 77 * This means that we need an 8-byte-odd alignment since the ABI expects 78 * the return address to be pushed, thus breaking the 16 byte alignment. 79 */ 80 sp -= 7; 81 82 /* Add the arguments: */ 83 va_start(ap, argc); 84 for (i = 0; i < argc; i++) 85 args[i] = va_arg(ap, uint64_t); 86 va_end(ap); 87 for (i = argc; i < 6; i++) 88 args[i] = 0; 89 90 ucp->uc_mcontext.mc_rdi = (register_t)ucp; 91 ucp->uc_mcontext.mc_rsi = (register_t)start; 92 ucp->uc_mcontext.mc_rdx = (register_t)args; 93 ucp->uc_mcontext.mc_rbp = 0; 94 ucp->uc_mcontext.mc_rbx = (register_t)sp; 95 ucp->uc_mcontext.mc_rsp = (register_t)sp; 96 ucp->uc_mcontext.mc_rip = (register_t)makectx_wrapper; 97 } 98 99 static void 100 makectx_wrapper(ucontext_t *ucp, func_t func, uint64_t *args) 101 { 102 (*func)(args[0], args[1], args[2], args[3], args[4], args[5]); 103 if (ucp->uc_link == NULL) 104 exit(0); 105 setcontext((const ucontext_t *)ucp->uc_link); 106 /* should never get here */ 107 abort(); 108 /* NOTREACHED */ 109 } 110