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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* Copyright (c) 1988 AT&T */ 30 /* All Rights Reserved */ 31 32 33 #pragma weak makecontext = _makecontext 34 #pragma weak __makecontext_v2 = ___makecontext_v2 35 36 #include "synonyms.h" 37 #include <stdarg.h> 38 #include <strings.h> 39 #include <sys/ucontext.h> 40 #include <sys/stack.h> 41 #include <sys/frame.h> 42 43 /* 44 * The ucontext_t that the user passes in must have been primed with a 45 * call to getcontext(2), have the uc_stack member set to reflect the 46 * stack which this context will use, and have the uc_link member set 47 * to the context which should be resumed when this context returns. 48 * When makecontext() returns, the ucontext_t will be set to run the 49 * given function with the given parameters on the stack specified by 50 * uc_stack, and which will return to the ucontext_t specified by uc_link. 51 */ 52 53 static void resumecontext(void); 54 55 void 56 _makecontext(ucontext_t *ucp, void (*func)(), int argc, ...) 57 { 58 greg_t *reg; 59 long *tsp; 60 char *sp; 61 int argno; 62 va_list ap; 63 size_t size; 64 65 reg = ucp->uc_mcontext.gregs; 66 reg[REG_PC] = (greg_t)func; 67 reg[REG_nPC] = reg[REG_PC] + 0x4; 68 69 /* 70 * Reserve enough space for a frame and the arguments beyond the 71 * sixth; round to stack alignment. 72 */ 73 size = sizeof (struct frame); 74 size += (argc > 6 ? argc - 6 : 0) * sizeof (long); 75 76 /* 77 * The legacy implemenation of makecontext() on sparc has been to 78 * interpret the uc_stack.ss_sp member incorrectly as the top of the 79 * stack rather than the base. We preserve this behavior here, but 80 * provide the correct semantics in __makecontext_v2(). 81 */ 82 sp = (char *)(((uintptr_t)ucp->uc_stack.ss_sp - size) & 83 ~(STACK_ALIGN - 1)); 84 85 /* 86 * Copy all args to the stack, and put the first 6 args into the 87 * ucontext_t. Zero the other fields of the frame. 88 */ 89 /* LINTED pointer cast may result in improper alignment */ 90 tsp = &((struct frame *)sp)->fr_argd[0]; 91 bzero(sp, sizeof (struct frame)); 92 93 va_start(ap, argc); 94 95 for (argno = 0; argno < argc; argno++) { 96 if (argno < 6) 97 *tsp++ = reg[REG_O0 + argno] = va_arg(ap, long); 98 else 99 *tsp++ = va_arg(ap, long); 100 } 101 102 va_end(ap); 103 104 reg[REG_SP] = (greg_t)sp - STACK_BIAS; /* sp (when done) */ 105 reg[REG_O7] = (greg_t)resumecontext - 8; /* return pc */ 106 } 107 108 void 109 __makecontext_v2(ucontext_t *ucp, void (*func)(), int argc, ...) 110 { 111 greg_t *reg; 112 long *tsp; 113 char *sp; 114 int argno; 115 va_list ap; 116 size_t size; 117 118 reg = ucp->uc_mcontext.gregs; 119 reg[REG_PC] = (greg_t)func; 120 reg[REG_nPC] = reg[REG_PC] + 0x4; 121 122 /* 123 * Reserve enough space for a frame and the arguments beyond the 124 * sixth; round to stack alignment. 125 */ 126 size = sizeof (struct frame); 127 size += (argc > 6 ? argc - 6 : 0) * sizeof (long); 128 129 sp = (char *)(((uintptr_t)ucp->uc_stack.ss_sp + 130 ucp->uc_stack.ss_size - size) & ~(STACK_ALIGN - 1)); 131 132 /* 133 * Copy all args to the stack, and put the first 6 args into the 134 * ucontext_t. Zero the other fields of the frame. 135 */ 136 /* LINTED pointer cast may result in improper alignment */ 137 tsp = &((struct frame *)sp)->fr_argd[0]; 138 bzero(sp, sizeof (struct frame)); 139 140 va_start(ap, argc); 141 142 for (argno = 0; argno < argc; argno++) { 143 if (argno < 6) 144 *tsp++ = reg[REG_O0 + argno] = va_arg(ap, long); 145 else 146 *tsp++ = va_arg(ap, long); 147 } 148 149 va_end(ap); 150 151 reg[REG_SP] = (greg_t)sp - STACK_BIAS; /* sp (when done) */ 152 reg[REG_O7] = (greg_t)resumecontext - 8; /* return pc */ 153 } 154 155 static void 156 resumecontext(void) 157 { 158 /* 159 * We can't include ucontext.h (where these functions are defined) 160 * because it remaps the symbol makecontext. 161 */ 162 extern int getcontext(ucontext_t *); 163 extern int setcontext(const ucontext_t *); 164 ucontext_t uc; 165 166 (void) getcontext(&uc); 167 (void) setcontext(uc.uc_link); 168 } 169