1d915a14eSPedro F. Giffuni /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3d915a14eSPedro F. Giffuni * 4840b91ccSNathan Whitehorn * Copyright (c) 2004 Suleiman Souhlal 5840b91ccSNathan Whitehorn * All rights reserved. 6840b91ccSNathan Whitehorn * 7840b91ccSNathan Whitehorn * Redistribution and use in source and binary forms, with or without 8840b91ccSNathan Whitehorn * modification, are permitted provided that the following conditions 9840b91ccSNathan Whitehorn * are met: 10840b91ccSNathan Whitehorn * 1. Redistributions of source code must retain the above copyright 11840b91ccSNathan Whitehorn * notice, this list of conditions and the following disclaimer. 12840b91ccSNathan Whitehorn * 2. Redistributions in binary form must reproduce the above copyright 13840b91ccSNathan Whitehorn * notice, this list of conditions and the following disclaimer in the 14840b91ccSNathan Whitehorn * documentation and/or other materials provided with the distribution. 15840b91ccSNathan Whitehorn * 16840b91ccSNathan Whitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17840b91ccSNathan Whitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18840b91ccSNathan Whitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19840b91ccSNathan Whitehorn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20840b91ccSNathan Whitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21840b91ccSNathan Whitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22840b91ccSNathan Whitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23840b91ccSNathan Whitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24840b91ccSNathan Whitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25840b91ccSNathan Whitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26840b91ccSNathan Whitehorn * SUCH DAMAGE. 27840b91ccSNathan Whitehorn */ 28840b91ccSNathan Whitehorn 29840b91ccSNathan Whitehorn #include <sys/param.h> 30840b91ccSNathan Whitehorn 31840b91ccSNathan Whitehorn #include <stdarg.h> 32840b91ccSNathan Whitehorn #include <stdlib.h> 33840b91ccSNathan Whitehorn #include <unistd.h> 34840b91ccSNathan Whitehorn #include <stdio.h> 35840b91ccSNathan Whitehorn #include <ucontext.h> 36840b91ccSNathan Whitehorn 37840b91ccSNathan Whitehorn __weak_reference(__makecontext, makecontext); 38840b91ccSNathan Whitehorn 39840b91ccSNathan Whitehorn void _ctx_done(ucontext_t *ucp); 40840b91ccSNathan Whitehorn void _ctx_start(void); 41840b91ccSNathan Whitehorn 42840b91ccSNathan Whitehorn void 43840b91ccSNathan Whitehorn _ctx_done(ucontext_t *ucp) 44840b91ccSNathan Whitehorn { 45840b91ccSNathan Whitehorn if (ucp->uc_link == NULL) 46840b91ccSNathan Whitehorn exit(0); 47840b91ccSNathan Whitehorn else { 48840b91ccSNathan Whitehorn /* invalidate context */ 49840b91ccSNathan Whitehorn ucp->uc_mcontext.mc_len = 0; 50840b91ccSNathan Whitehorn 51840b91ccSNathan Whitehorn setcontext((const ucontext_t *)ucp->uc_link); 52840b91ccSNathan Whitehorn 53840b91ccSNathan Whitehorn abort(); /* should never return from above call */ 54840b91ccSNathan Whitehorn } 55840b91ccSNathan Whitehorn } 56840b91ccSNathan Whitehorn 57840b91ccSNathan Whitehorn void 58840b91ccSNathan Whitehorn __makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...) 59840b91ccSNathan Whitehorn { 60840b91ccSNathan Whitehorn mcontext_t *mc; 61840b91ccSNathan Whitehorn char *sp; 62840b91ccSNathan Whitehorn va_list ap; 63840b91ccSNathan Whitehorn int i, regargs, stackargs; 64840b91ccSNathan Whitehorn 65840b91ccSNathan Whitehorn /* Sanity checks */ 6680996ef8SJohn Baldwin if ((ucp == NULL) || (argc < 0) 67840b91ccSNathan Whitehorn || (ucp->uc_stack.ss_sp == NULL) 68840b91ccSNathan Whitehorn || (ucp->uc_stack.ss_size < MINSIGSTKSZ)) { 69840b91ccSNathan Whitehorn /* invalidate context */ 70840b91ccSNathan Whitehorn ucp->uc_mcontext.mc_len = 0; 71840b91ccSNathan Whitehorn return; 72840b91ccSNathan Whitehorn } 73840b91ccSNathan Whitehorn 74840b91ccSNathan Whitehorn /* 75840b91ccSNathan Whitehorn * The stack must have space for the frame pointer, saved 76840b91ccSNathan Whitehorn * link register, overflow arguments, and be 16-byte 77840b91ccSNathan Whitehorn * aligned. 78840b91ccSNathan Whitehorn */ 79840b91ccSNathan Whitehorn stackargs = (argc > 8) ? argc - 8 : 0; 80840b91ccSNathan Whitehorn sp = (char *) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size 81840b91ccSNathan Whitehorn - sizeof(uintptr_t)*(stackargs + 2); 82840b91ccSNathan Whitehorn sp = (char *)((uintptr_t)sp & ~0x1f); 83840b91ccSNathan Whitehorn 84840b91ccSNathan Whitehorn mc = &ucp->uc_mcontext; 85840b91ccSNathan Whitehorn 86840b91ccSNathan Whitehorn /* 87840b91ccSNathan Whitehorn * Up to 8 register args. Assumes all args are 64-bit and 88840b91ccSNathan Whitehorn * integer only. Not sure how to cater for floating point. 89840b91ccSNathan Whitehorn */ 90840b91ccSNathan Whitehorn regargs = (argc > 8) ? 8 : argc; 91840b91ccSNathan Whitehorn va_start(ap, argc); 92840b91ccSNathan Whitehorn for (i = 0; i < regargs; i++) 93840b91ccSNathan Whitehorn mc->mc_gpr[3 + i] = va_arg(ap, uint64_t); 94840b91ccSNathan Whitehorn 95840b91ccSNathan Whitehorn /* 96840b91ccSNathan Whitehorn * Overflow args go onto the stack 97840b91ccSNathan Whitehorn */ 98840b91ccSNathan Whitehorn if (argc > 8) { 99840b91ccSNathan Whitehorn uint64_t *argp; 100840b91ccSNathan Whitehorn 101840b91ccSNathan Whitehorn /* Skip past frame pointer and saved LR */ 102e039e3d1SBrandon Bergren #if !defined(_CALL_ELF) || _CALL_ELF == 1 103840b91ccSNathan Whitehorn argp = (uint64_t *)sp + 6; 104e039e3d1SBrandon Bergren #else 105e039e3d1SBrandon Bergren argp = (uint64_t *)sp + 4; 106e039e3d1SBrandon Bergren #endif 107840b91ccSNathan Whitehorn 108840b91ccSNathan Whitehorn for (i = 0; i < stackargs; i++) 109840b91ccSNathan Whitehorn *argp++ = va_arg(ap, uint64_t); 110840b91ccSNathan Whitehorn } 111840b91ccSNathan Whitehorn va_end(ap); 112840b91ccSNathan Whitehorn 113840b91ccSNathan Whitehorn /* 114840b91ccSNathan Whitehorn * Use caller-saved regs 14/15 to hold params that _ctx_start 115840b91ccSNathan Whitehorn * will use to invoke the user-supplied func 116840b91ccSNathan Whitehorn */ 1177316504cSBrandon Bergren #if !defined(_CALL_ELF) || _CALL_ELF == 1 1187316504cSBrandon Bergren /* Cast to ensure this is treated as a function descriptor. */ 119351f3052SNathan Whitehorn mc->mc_srr0 = *(uintptr_t *)_ctx_start; 1207316504cSBrandon Bergren #else 1217316504cSBrandon Bergren mc->mc_srr0 = (uintptr_t) _ctx_start; 1227316504cSBrandon Bergren #endif 123840b91ccSNathan Whitehorn mc->mc_gpr[1] = (uintptr_t) sp; /* new stack pointer */ 124840b91ccSNathan Whitehorn mc->mc_gpr[14] = (uintptr_t) start; /* r14 <- start */ 125840b91ccSNathan Whitehorn mc->mc_gpr[15] = (uintptr_t) ucp; /* r15 <- ucp */ 126840b91ccSNathan Whitehorn } 127