/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2003 Marcel Moolenaar4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9*10* 1. Redistributions of source code must retain the above copyright11* notice, this list of conditions and the following disclaimer.12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR17* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES18* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.19* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,20* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT21* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,22* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY23* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT24* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF25* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.26*/2728#include <sys/types.h>29#include <sys/ucontext.h>30#include <stdarg.h>31#include <stdlib.h>3233typedef void (*func_t)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t,34uint64_t);3536/* Prototypes */37static void makectx_wrapper(ucontext_t *ucp, func_t func, uint64_t *args);3839__weak_reference(__makecontext, makecontext);4041void42__makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...)43{44uint64_t *args;45uint64_t *sp;46va_list ap;47int i;4849/* A valid context is required. */50if ((ucp == NULL) || (ucp->uc_mcontext.mc_len != sizeof(mcontext_t)))51return;52else if ((argc < 0) || (argc > 6) || (ucp->uc_stack.ss_sp == NULL) ||53(ucp->uc_stack.ss_size < MINSIGSTKSZ)) {54/*55* This should really return -1 with errno set to ENOMEM56* or something, but the spec says that makecontext is57* a void function. At least make sure that the context58* isn't valid so it can't be used without an error.59*/60ucp->uc_mcontext.mc_len = 0;61return;62}6364/* Align the stack to 16 bytes. */65sp = (uint64_t *)(ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);66sp = (uint64_t *)((uint64_t)sp & ~15UL);6768/* Allocate space for a maximum of 6 arguments on the stack. */69args = sp - 6;7071/*72* Account for arguments on stack and do the funky C entry alignment.73* This means that we need an 8-byte-odd alignment since the ABI expects74* the return address to be pushed, thus breaking the 16 byte alignment.75*/76sp -= 7;7778/* Add the arguments: */79va_start(ap, argc);80for (i = 0; i < argc; i++)81args[i] = va_arg(ap, uint64_t);82va_end(ap);83for (i = argc; i < 6; i++)84args[i] = 0;8586ucp->uc_mcontext.mc_rdi = (register_t)ucp;87ucp->uc_mcontext.mc_rsi = (register_t)start;88ucp->uc_mcontext.mc_rdx = (register_t)args;89ucp->uc_mcontext.mc_rbp = 0;90ucp->uc_mcontext.mc_rbx = (register_t)sp;91ucp->uc_mcontext.mc_rsp = (register_t)sp;92ucp->uc_mcontext.mc_rip = (register_t)makectx_wrapper;93}9495static void96makectx_wrapper(ucontext_t *ucp, func_t func, uint64_t *args)97{98(*func)(args[0], args[1], args[2], args[3], args[4], args[5]);99if (ucp->uc_link == NULL)100exit(0);101setcontext((const ucontext_t *)ucp->uc_link);102/* should never get here */103abort();104/* NOTREACHED */105}106107108