1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 #pragma weak _makecontext = makecontext 31 32 #include "lint.h" 33 #include <stdarg.h> 34 #include <ucontext.h> 35 #include <sys/stack.h> 36 37 /* 38 * The ucontext_t that the user passes in must have been primed with a 39 * call to getcontext(2), have the uc_stack member set to reflect the 40 * stack which this context will use, and have the uc_link member set 41 * to the context which should be resumed when this context returns. 42 * When makecontext() returns, the ucontext_t will be set to run the 43 * given function with the given parameters on the stack specified by 44 * uc_stack, and which will return to the ucontext_t specified by uc_link. 45 */ 46 47 /* 48 * The original i386 ABI said that the stack pointer need be only 4-byte 49 * aligned before a function call (STACK_ALIGN == 4). The ABI supplement 50 * version 1.0 changed the required alignment to 16-byte for the benefit of 51 * floating point code compiled using sse2. The compiler assumes this 52 * alignment and maintains it for calls it generates. If the stack is 53 * initially properly aligned, it will continue to be so aligned. If it is 54 * not initially so aligned, it will never become so aligned. 55 * 56 * One slightly confusing detail to keep in mind is that the 16-byte 57 * alignment (%esp & 0xf == 0) is true just *before* the call instruction. 58 * The call instruction will then push a return value, decrementing %esp by 59 * 4. Therefore, if one dumps %esp at the at the very first instruction in 60 * a function, it will end with a 0xc. The compiler expects this and 61 * compensates for it properly. 62 * 63 * Note: If you change this value, you need to change it in the following 64 * files as well: 65 * 66 * - lib/libc/i386/threads/machdep.c 67 * - lib/crt/i86/crti.s 68 * - lib/crt/i86/crt1.s 69 */ 70 #undef STACK_ALIGN 71 #define STACK_ALIGN 16 72 73 static void resumecontext(void); 74 75 void 76 makecontext(ucontext_t *ucp, void (*func)(), int argc, ...) 77 { 78 long *sp; 79 long *tsp; 80 va_list ap; 81 size_t size; 82 83 ucp->uc_mcontext.gregs[EIP] = (greg_t)func; 84 85 size = sizeof (long) * (argc + 1); 86 87 tsp = (long *)(((uintptr_t)ucp->uc_stack.ss_sp + 88 ucp->uc_stack.ss_size - size) & ~(STACK_ALIGN - 1)); 89 90 /* 91 * Since we're emulating the call instruction, we must push the 92 * return address (which involves adjusting the stack pointer to 93 * have the proper 4-byte bias). 94 */ 95 sp = tsp - 1; 96 97 *sp = (long)resumecontext; /* return address */ 98 99 ucp->uc_mcontext.gregs[UESP] = (greg_t)sp; 100 101 /* 102 * "push" all the arguments 103 */ 104 va_start(ap, argc); 105 while (argc-- > 0) 106 *tsp++ = va_arg(ap, long); 107 va_end(ap); 108 } 109 110 111 static void 112 resumecontext(void) 113 { 114 ucontext_t uc; 115 116 (void) getcontext(&uc); 117 (void) setcontext(uc.uc_link); 118 }