1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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/types.h> 30 #include <sys/ucontext.h> 31 #include <stdarg.h> 32 #include <stdlib.h> 33 34 typedef void (*func_t)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, 35 uint64_t); 36 37 /* Prototypes */ 38 static void makectx_wrapper(ucontext_t *ucp, func_t func, uint64_t *args); 39 40 __weak_reference(__makecontext, makecontext); 41 42 void 43 __makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...) 44 { 45 uint64_t *args; 46 uint64_t *sp; 47 va_list ap; 48 int i; 49 50 /* A valid context is required. */ 51 if ((ucp == NULL) || (ucp->uc_mcontext.mc_len != sizeof(mcontext_t))) 52 return; 53 else if ((argc < 0) || (argc > 6) || (ucp->uc_stack.ss_sp == NULL) || 54 (ucp->uc_stack.ss_size < MINSIGSTKSZ)) { 55 /* 56 * This should really return -1 with errno set to ENOMEM 57 * or something, but the spec says that makecontext is 58 * a void function. At least make sure that the context 59 * isn't valid so it can't be used without an error. 60 */ 61 ucp->uc_mcontext.mc_len = 0; 62 return; 63 } 64 65 /* Align the stack to 16 bytes. */ 66 sp = (uint64_t *)(ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size); 67 sp = (uint64_t *)((uint64_t)sp & ~15UL); 68 69 /* Allocate space for a maximum of 6 arguments on the stack. */ 70 args = sp - 6; 71 72 /* 73 * Account for arguments on stack and do the funky C entry alignment. 74 * This means that we need an 8-byte-odd alignment since the ABI expects 75 * the return address to be pushed, thus breaking the 16 byte alignment. 76 */ 77 sp -= 7; 78 79 /* Add the arguments: */ 80 va_start(ap, argc); 81 for (i = 0; i < argc; i++) 82 args[i] = va_arg(ap, uint64_t); 83 va_end(ap); 84 for (i = argc; i < 6; i++) 85 args[i] = 0; 86 87 ucp->uc_mcontext.mc_rdi = (register_t)ucp; 88 ucp->uc_mcontext.mc_rsi = (register_t)start; 89 ucp->uc_mcontext.mc_rdx = (register_t)args; 90 ucp->uc_mcontext.mc_rbp = 0; 91 ucp->uc_mcontext.mc_rbx = (register_t)sp; 92 ucp->uc_mcontext.mc_rsp = (register_t)sp; 93 ucp->uc_mcontext.mc_rip = (register_t)makectx_wrapper; 94 } 95 96 static void 97 makectx_wrapper(ucontext_t *ucp, func_t func, uint64_t *args) 98 { 99 (*func)(args[0], args[1], args[2], args[3], args[4], args[5]); 100 if (ucp->uc_link == NULL) 101 exit(0); 102 setcontext((const ucontext_t *)ucp->uc_link); 103 /* should never get here */ 104 abort(); 105 /* NOTREACHED */ 106 } 107