17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57257d1b4Sraf * Common Development and Distribution License (the "License"). 67257d1b4Sraf * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217257d1b4Sraf 227c478bd9Sstevel@tonic-gate /* 237257d1b4Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */ 287c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 297c478bd9Sstevel@tonic-gate 307257d1b4Sraf #pragma weak _makecontext = makecontext 317c478bd9Sstevel@tonic-gate 327257d1b4Sraf #include "lint.h" 337c478bd9Sstevel@tonic-gate #include <stdarg.h> 347c478bd9Sstevel@tonic-gate #include <ucontext.h> 357c478bd9Sstevel@tonic-gate #include <sys/stack.h> 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate /* 387c478bd9Sstevel@tonic-gate * The ucontext_t that the user passes in must have been primed with a 397c478bd9Sstevel@tonic-gate * call to getcontext(2), have the uc_stack member set to reflect the 407c478bd9Sstevel@tonic-gate * stack which this context will use, and have the uc_link member set 417c478bd9Sstevel@tonic-gate * to the context which should be resumed when this context returns. 427c478bd9Sstevel@tonic-gate * When makecontext() returns, the ucontext_t will be set to run the 437c478bd9Sstevel@tonic-gate * given function with the given parameters on the stack specified by 447c478bd9Sstevel@tonic-gate * uc_stack, and which will return to the ucontext_t specified by uc_link. 457c478bd9Sstevel@tonic-gate */ 467c478bd9Sstevel@tonic-gate 47ceef08daSJosef 'Jeff' Sipek /* 48ceef08daSJosef 'Jeff' Sipek * The original i386 ABI said that the stack pointer need be only 4-byte 49ceef08daSJosef 'Jeff' Sipek * aligned before a function call (STACK_ALIGN == 4). The ABI supplement 50ceef08daSJosef 'Jeff' Sipek * version 1.0 changed the required alignment to 16-byte for the benefit of 51ceef08daSJosef 'Jeff' Sipek * floating point code compiled using sse2. The compiler assumes this 52ceef08daSJosef 'Jeff' Sipek * alignment and maintains it for calls it generates. If the stack is 53ceef08daSJosef 'Jeff' Sipek * initially properly aligned, it will continue to be so aligned. If it is 54ceef08daSJosef 'Jeff' Sipek * not initially so aligned, it will never become so aligned. 55ceef08daSJosef 'Jeff' Sipek * 56ceef08daSJosef 'Jeff' Sipek * One slightly confusing detail to keep in mind is that the 16-byte 57ceef08daSJosef 'Jeff' Sipek * alignment (%esp & 0xf == 0) is true just *before* the call instruction. 58ceef08daSJosef 'Jeff' Sipek * The call instruction will then push a return value, decrementing %esp by 59ceef08daSJosef 'Jeff' Sipek * 4. Therefore, if one dumps %esp at the at the very first instruction in 60ceef08daSJosef 'Jeff' Sipek * a function, it will end with a 0xc. The compiler expects this and 61ceef08daSJosef 'Jeff' Sipek * compensates for it properly. 62ceef08daSJosef 'Jeff' Sipek * 63ceef08daSJosef 'Jeff' Sipek * Note: If you change this value, you need to change it in the following 64ceef08daSJosef 'Jeff' Sipek * files as well: 65ceef08daSJosef 'Jeff' Sipek * 66ceef08daSJosef 'Jeff' Sipek * - lib/libc/i386/threads/machdep.c 67*3e0c8044SRichard Lowe * - lib/crt/i386/crti.s 68*3e0c8044SRichard Lowe * - lib/crt/i386/crt1.s 69ceef08daSJosef 'Jeff' Sipek */ 70ceef08daSJosef 'Jeff' Sipek #undef STACK_ALIGN 71ceef08daSJosef 'Jeff' Sipek #define STACK_ALIGN 16 72ceef08daSJosef 'Jeff' Sipek 737c478bd9Sstevel@tonic-gate static void resumecontext(void); 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate void 767c478bd9Sstevel@tonic-gate makecontext(ucontext_t *ucp, void (*func)(), int argc, ...) 777c478bd9Sstevel@tonic-gate { 787c478bd9Sstevel@tonic-gate long *sp; 797c478bd9Sstevel@tonic-gate long *tsp; 807c478bd9Sstevel@tonic-gate va_list ap; 817c478bd9Sstevel@tonic-gate size_t size; 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate ucp->uc_mcontext.gregs[EIP] = (greg_t)func; 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate size = sizeof (long) * (argc + 1); 867c478bd9Sstevel@tonic-gate 87ceef08daSJosef 'Jeff' Sipek tsp = (long *)(((uintptr_t)ucp->uc_stack.ss_sp + 887c478bd9Sstevel@tonic-gate ucp->uc_stack.ss_size - size) & ~(STACK_ALIGN - 1)); 897c478bd9Sstevel@tonic-gate 90ceef08daSJosef 'Jeff' Sipek /* 91ceef08daSJosef 'Jeff' Sipek * Since we're emulating the call instruction, we must push the 92ceef08daSJosef 'Jeff' Sipek * return address (which involves adjusting the stack pointer to 93ceef08daSJosef 'Jeff' Sipek * have the proper 4-byte bias). 94ceef08daSJosef 'Jeff' Sipek */ 95ceef08daSJosef 'Jeff' Sipek sp = tsp - 1; 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate *sp = (long)resumecontext; /* return address */ 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate ucp->uc_mcontext.gregs[UESP] = (greg_t)sp; 100ceef08daSJosef 'Jeff' Sipek 101ceef08daSJosef 'Jeff' Sipek /* 102ceef08daSJosef 'Jeff' Sipek * "push" all the arguments 103ceef08daSJosef 'Jeff' Sipek */ 104ceef08daSJosef 'Jeff' Sipek va_start(ap, argc); 105ceef08daSJosef 'Jeff' Sipek while (argc-- > 0) 106ceef08daSJosef 'Jeff' Sipek *tsp++ = va_arg(ap, long); 107ceef08daSJosef 'Jeff' Sipek va_end(ap); 1087c478bd9Sstevel@tonic-gate } 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate static void 1127c478bd9Sstevel@tonic-gate resumecontext(void) 1137c478bd9Sstevel@tonic-gate { 1147c478bd9Sstevel@tonic-gate ucontext_t uc; 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate (void) getcontext(&uc); 1177c478bd9Sstevel@tonic-gate (void) setcontext(uc.uc_link); 1187c478bd9Sstevel@tonic-gate } 119