1d915a14eSPedro F. Giffuni /*- 2d915a14eSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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/cdefs.h> 30840b91ccSNathan Whitehorn __FBSDID("$FreeBSD$"); 31840b91ccSNathan Whitehorn 32840b91ccSNathan Whitehorn #include <sys/param.h> 33840b91ccSNathan Whitehorn 34840b91ccSNathan Whitehorn #include <stdarg.h> 35840b91ccSNathan Whitehorn #include <stdlib.h> 36840b91ccSNathan Whitehorn #include <unistd.h> 37840b91ccSNathan Whitehorn #include <stdio.h> 38840b91ccSNathan Whitehorn #include <ucontext.h> 39840b91ccSNathan Whitehorn 40840b91ccSNathan Whitehorn __weak_reference(__makecontext, makecontext); 41840b91ccSNathan Whitehorn 42840b91ccSNathan Whitehorn void _ctx_done(ucontext_t *ucp); 43840b91ccSNathan Whitehorn void _ctx_start(void); 44840b91ccSNathan Whitehorn 45840b91ccSNathan Whitehorn void 46840b91ccSNathan Whitehorn _ctx_done(ucontext_t *ucp) 47840b91ccSNathan Whitehorn { 48840b91ccSNathan Whitehorn if (ucp->uc_link == NULL) 49840b91ccSNathan Whitehorn exit(0); 50840b91ccSNathan Whitehorn else { 51840b91ccSNathan Whitehorn /* invalidate context */ 52840b91ccSNathan Whitehorn ucp->uc_mcontext.mc_len = 0; 53840b91ccSNathan Whitehorn 54840b91ccSNathan Whitehorn setcontext((const ucontext_t *)ucp->uc_link); 55840b91ccSNathan Whitehorn 56840b91ccSNathan Whitehorn abort(); /* should never return from above call */ 57840b91ccSNathan Whitehorn } 58840b91ccSNathan Whitehorn } 59840b91ccSNathan Whitehorn 60840b91ccSNathan Whitehorn void 61840b91ccSNathan Whitehorn __makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...) 62840b91ccSNathan Whitehorn { 63840b91ccSNathan Whitehorn mcontext_t *mc; 64840b91ccSNathan Whitehorn char *sp; 65840b91ccSNathan Whitehorn va_list ap; 66840b91ccSNathan Whitehorn int i, regargs, stackargs; 67840b91ccSNathan Whitehorn 68840b91ccSNathan Whitehorn /* Sanity checks */ 6980996ef8SJohn Baldwin if ((ucp == NULL) || (argc < 0) 70840b91ccSNathan Whitehorn || (ucp->uc_stack.ss_sp == NULL) 71840b91ccSNathan Whitehorn || (ucp->uc_stack.ss_size < MINSIGSTKSZ)) { 72840b91ccSNathan Whitehorn /* invalidate context */ 73840b91ccSNathan Whitehorn ucp->uc_mcontext.mc_len = 0; 74840b91ccSNathan Whitehorn return; 75840b91ccSNathan Whitehorn } 76840b91ccSNathan Whitehorn 77840b91ccSNathan Whitehorn /* 78840b91ccSNathan Whitehorn * The stack must have space for the frame pointer, saved 79840b91ccSNathan Whitehorn * link register, overflow arguments, and be 16-byte 80840b91ccSNathan Whitehorn * aligned. 81840b91ccSNathan Whitehorn */ 82840b91ccSNathan Whitehorn stackargs = (argc > 8) ? argc - 8 : 0; 83840b91ccSNathan Whitehorn sp = (char *) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size 84840b91ccSNathan Whitehorn - sizeof(uintptr_t)*(stackargs + 2); 85840b91ccSNathan Whitehorn sp = (char *)((uintptr_t)sp & ~0x1f); 86840b91ccSNathan Whitehorn 87840b91ccSNathan Whitehorn mc = &ucp->uc_mcontext; 88840b91ccSNathan Whitehorn 89840b91ccSNathan Whitehorn /* 90840b91ccSNathan Whitehorn * Up to 8 register args. Assumes all args are 64-bit and 91840b91ccSNathan Whitehorn * integer only. Not sure how to cater for floating point. 92840b91ccSNathan Whitehorn */ 93840b91ccSNathan Whitehorn regargs = (argc > 8) ? 8 : argc; 94840b91ccSNathan Whitehorn va_start(ap, argc); 95840b91ccSNathan Whitehorn for (i = 0; i < regargs; i++) 96840b91ccSNathan Whitehorn mc->mc_gpr[3 + i] = va_arg(ap, uint64_t); 97840b91ccSNathan Whitehorn 98840b91ccSNathan Whitehorn /* 99840b91ccSNathan Whitehorn * Overflow args go onto the stack 100840b91ccSNathan Whitehorn */ 101840b91ccSNathan Whitehorn if (argc > 8) { 102840b91ccSNathan Whitehorn uint64_t *argp; 103840b91ccSNathan Whitehorn 104840b91ccSNathan Whitehorn /* Skip past frame pointer and saved LR */ 105*e039e3d1SBrandon Bergren #if !defined(_CALL_ELF) || _CALL_ELF == 1 106840b91ccSNathan Whitehorn argp = (uint64_t *)sp + 6; 107*e039e3d1SBrandon Bergren #else 108*e039e3d1SBrandon Bergren argp = (uint64_t *)sp + 4; 109*e039e3d1SBrandon Bergren #endif 110840b91ccSNathan Whitehorn 111840b91ccSNathan Whitehorn for (i = 0; i < stackargs; i++) 112840b91ccSNathan Whitehorn *argp++ = va_arg(ap, uint64_t); 113840b91ccSNathan Whitehorn } 114840b91ccSNathan Whitehorn va_end(ap); 115840b91ccSNathan Whitehorn 116840b91ccSNathan Whitehorn /* 117840b91ccSNathan Whitehorn * Use caller-saved regs 14/15 to hold params that _ctx_start 118840b91ccSNathan Whitehorn * will use to invoke the user-supplied func 119840b91ccSNathan Whitehorn */ 1207316504cSBrandon Bergren #if !defined(_CALL_ELF) || _CALL_ELF == 1 1217316504cSBrandon Bergren /* Cast to ensure this is treated as a function descriptor. */ 122351f3052SNathan Whitehorn mc->mc_srr0 = *(uintptr_t *)_ctx_start; 1237316504cSBrandon Bergren #else 1247316504cSBrandon Bergren mc->mc_srr0 = (uintptr_t) _ctx_start; 1257316504cSBrandon Bergren #endif 126840b91ccSNathan Whitehorn mc->mc_gpr[1] = (uintptr_t) sp; /* new stack pointer */ 127840b91ccSNathan Whitehorn mc->mc_gpr[14] = (uintptr_t) start; /* r14 <- start */ 128840b91ccSNathan Whitehorn mc->mc_gpr[15] = (uintptr_t) ucp; /* r15 <- ucp */ 129840b91ccSNathan Whitehorn } 130