1126475Sgrehan/* 2126475Sgrehan * Copyright (c) 2004 Suleiman Souhlal 3126475Sgrehan * All rights reserved. 4126475Sgrehan * 5126475Sgrehan * Redistribution and use in source and binary forms, with or without 6126475Sgrehan * modification, are permitted provided that the following conditions 7126475Sgrehan * are met: 8126475Sgrehan * 1. Redistributions of source code must retain the above copyright 9126475Sgrehan * notice, this list of conditions and the following disclaimer. 10126475Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 11126475Sgrehan * notice, this list of conditions and the following disclaimer in the 12126475Sgrehan * documentation and/or other materials provided with the distribution. 13126475Sgrehan * 14126475Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15126475Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16126475Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17126475Sgrehan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18126475Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19126475Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20126475Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21126475Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22126475Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23126475Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24126475Sgrehan * SUCH DAMAGE. 25126475Sgrehan */ 26126475Sgrehan 27126475Sgrehan#include <sys/cdefs.h> 28126475Sgrehan__FBSDID("$FreeBSD: releng/11.0/lib/libc/powerpc/gen/makecontext.c 132398 2004-07-19 12:05:07Z grehan $"); 29126475Sgrehan 30126475Sgrehan#include <sys/param.h> 31126475Sgrehan 32126475Sgrehan#include <stdarg.h> 33126475Sgrehan#include <stdlib.h> 34126475Sgrehan#include <unistd.h> 35126475Sgrehan#include <stdio.h> 36126475Sgrehan#include <ucontext.h> 37126475Sgrehan 38126475Sgrehan__weak_reference(__makecontext, makecontext); 39126475Sgrehan 40126475Sgrehanvoid _ctx_done(ucontext_t *ucp); 41126475Sgrehanvoid _ctx_start(void); 42126475Sgrehan 43126475Sgrehanvoid 44126475Sgrehan_ctx_done(ucontext_t *ucp) 45126475Sgrehan{ 46126475Sgrehan if (ucp->uc_link == NULL) 47126475Sgrehan exit(0); 48126475Sgrehan else { 49126475Sgrehan /* invalidate context */ 50126475Sgrehan ucp->uc_mcontext.mc_len = 0; 51126475Sgrehan 52126475Sgrehan setcontext((const ucontext_t *)ucp->uc_link); 53126475Sgrehan 54126475Sgrehan abort(); /* should never return from above call */ 55126475Sgrehan } 56126475Sgrehan} 57126475Sgrehan 58126475Sgrehanvoid 59126475Sgrehan__makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...) 60126475Sgrehan{ 61126475Sgrehan mcontext_t *mc; 62126475Sgrehan char *sp; 63126475Sgrehan va_list ap; 64126475Sgrehan int i, regargs, stackargs; 65126475Sgrehan 66126475Sgrehan /* Sanity checks */ 67126475Sgrehan if ((ucp == NULL) || (argc < 0) || (argc > NCARGS) 68126475Sgrehan || (ucp->uc_stack.ss_sp == NULL) 69126475Sgrehan || (ucp->uc_stack.ss_size < MINSIGSTKSZ)) { 70126475Sgrehan /* invalidate context */ 71126475Sgrehan ucp->uc_mcontext.mc_len = 0; 72126475Sgrehan return; 73126475Sgrehan } 74126475Sgrehan 75126475Sgrehan /* 76126475Sgrehan * The stack must have space for the frame pointer, saved 77126475Sgrehan * link register, overflow arguments, and be 16-byte 78126475Sgrehan * aligned. 79126475Sgrehan */ 80126475Sgrehan stackargs = (argc > 8) ? argc - 8 : 0; 81126475Sgrehan sp = (char *) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size 82126475Sgrehan - sizeof(uint32_t)*(stackargs + 2); 83126475Sgrehan sp = (char *)((uint32_t)sp & ~0x1f); 84126475Sgrehan 85126475Sgrehan mc = &ucp->uc_mcontext; 86126475Sgrehan 87126475Sgrehan /* 88126475Sgrehan * Up to 8 register args. Assumes all args are 32-bit and 89126475Sgrehan * integer only. Not sure how to cater for floating point, 90126475Sgrehan * although 64-bit args will work if aligned correctly 91126475Sgrehan * in the arg list. 92126475Sgrehan */ 93126475Sgrehan regargs = (argc > 8) ? 8 : argc; 94126475Sgrehan va_start(ap, argc); 95126475Sgrehan for (i = 0; i < regargs; i++) 96126475Sgrehan mc->mc_gpr[3 + i] = va_arg(ap, uint32_t); 97126475Sgrehan 98126475Sgrehan /* 99126475Sgrehan * Overflow args go onto the stack 100126475Sgrehan */ 101126475Sgrehan if (argc > 8) { 102126475Sgrehan uint32_t *argp; 103126475Sgrehan 104126475Sgrehan /* Skip past frame pointer and saved LR */ 105126475Sgrehan argp = (uint32_t *)sp + 2; 106126475Sgrehan 107126475Sgrehan for (i = 0; i < stackargs; i++) 108126475Sgrehan *argp++ = va_arg(ap, uint32_t); 109126475Sgrehan } 110126475Sgrehan va_end(ap); 111126475Sgrehan 112126475Sgrehan /* 113126475Sgrehan * Use caller-saved regs 14/15 to hold params that _ctx_start 114126475Sgrehan * will use to invoke the user-supplied func 115126475Sgrehan */ 116132398Sgrehan mc->mc_srr0 = (uint32_t) _ctx_start; 117126475Sgrehan mc->mc_gpr[1] = (uint32_t) sp; /* new stack pointer */ 118126475Sgrehan mc->mc_gpr[14] = (uint32_t) start; /* r14 <- start */ 119126475Sgrehan mc->mc_gpr[15] = (uint32_t) ucp; /* r15 <- ucp */ 120126475Sgrehan} 121