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 ident "%Z%%M% %I% %E% SMI" 31 32 #pragma weak _makecontext = makecontext 33 #pragma weak ___makecontext_v2 = __makecontext_v2 34 35 #include "lint.h" 36 #include <stdarg.h> 37 #include <strings.h> 38 #include <sys/ucontext.h> 39 #include <sys/stack.h> 40 #include <sys/frame.h> 41 42 /* 43 * The ucontext_t that the user passes in must have been primed with a 44 * call to getcontext(2), have the uc_stack member set to reflect the 45 * stack which this context will use, and have the uc_link member set 46 * to the context which should be resumed when this context returns. 47 * When makecontext() returns, the ucontext_t will be set to run the 48 * given function with the given parameters on the stack specified by 49 * uc_stack, and which will return to the ucontext_t specified by uc_link. 50 */ 51 52 static void resumecontext(void); 53 54 void 55 makecontext(ucontext_t *ucp, void (*func)(), int argc, ...) 56 { 57 greg_t *reg; 58 long *tsp; 59 char *sp; 60 int argno; 61 va_list ap; 62 size_t size; 63 64 reg = ucp->uc_mcontext.gregs; 65 reg[REG_PC] = (greg_t)func; 66 reg[REG_nPC] = reg[REG_PC] + 0x4; 67 68 /* 69 * Reserve enough space for a frame and the arguments beyond the 70 * sixth; round to stack alignment. 71 */ 72 size = sizeof (struct frame); 73 size += (argc > 6 ? argc - 6 : 0) * sizeof (long); 74 75 /* 76 * The legacy implemenation of makecontext() on sparc has been to 77 * interpret the uc_stack.ss_sp member incorrectly as the top of the 78 * stack rather than the base. We preserve this behavior here, but 79 * provide the correct semantics in __makecontext_v2(). 80 */ 81 sp = (char *)(((uintptr_t)ucp->uc_stack.ss_sp - size) & 82 ~(STACK_ALIGN - 1)); 83 84 /* 85 * Copy all args to the stack, and put the first 6 args into the 86 * ucontext_t. Zero the other fields of the frame. 87 */ 88 /* LINTED pointer cast may result in improper alignment */ 89 tsp = &((struct frame *)sp)->fr_argd[0]; 90 bzero(sp, sizeof (struct frame)); 91 92 va_start(ap, argc); 93 94 for (argno = 0; argno < argc; argno++) { 95 if (argno < 6) 96 *tsp++ = reg[REG_O0 + argno] = va_arg(ap, long); 97 else 98 *tsp++ = va_arg(ap, long); 99 } 100 101 va_end(ap); 102 103 reg[REG_SP] = (greg_t)sp - STACK_BIAS; /* sp (when done) */ 104 reg[REG_O7] = (greg_t)resumecontext - 8; /* return pc */ 105 } 106 107 void 108 __makecontext_v2(ucontext_t *ucp, void (*func)(), int argc, ...) 109 { 110 greg_t *reg; 111 long *tsp; 112 char *sp; 113 int argno; 114 va_list ap; 115 size_t size; 116 117 reg = ucp->uc_mcontext.gregs; 118 reg[REG_PC] = (greg_t)func; 119 reg[REG_nPC] = reg[REG_PC] + 0x4; 120 121 /* 122 * Reserve enough space for a frame and the arguments beyond the 123 * sixth; round to stack alignment. 124 */ 125 size = sizeof (struct frame); 126 size += (argc > 6 ? argc - 6 : 0) * sizeof (long); 127 128 sp = (char *)(((uintptr_t)ucp->uc_stack.ss_sp + 129 ucp->uc_stack.ss_size - size) & ~(STACK_ALIGN - 1)); 130 131 /* 132 * Copy all args to the stack, and put the first 6 args into the 133 * ucontext_t. Zero the other fields of the frame. 134 */ 135 /* LINTED pointer cast may result in improper alignment */ 136 tsp = &((struct frame *)sp)->fr_argd[0]; 137 bzero(sp, sizeof (struct frame)); 138 139 va_start(ap, argc); 140 141 for (argno = 0; argno < argc; argno++) { 142 if (argno < 6) 143 *tsp++ = reg[REG_O0 + argno] = va_arg(ap, long); 144 else 145 *tsp++ = va_arg(ap, long); 146 } 147 148 va_end(ap); 149 150 reg[REG_SP] = (greg_t)sp - STACK_BIAS; /* sp (when done) */ 151 reg[REG_O7] = (greg_t)resumecontext - 8; /* return pc */ 152 } 153 154 static void 155 resumecontext(void) 156 { 157 /* 158 * We can't include ucontext.h (where these functions are defined) 159 * because it remaps the symbol makecontext. 160 */ 161 extern int getcontext(ucontext_t *); 162 extern int setcontext(const ucontext_t *); 163 ucontext_t uc; 164 165 (void) getcontext(&uc); 166 (void) setcontext(uc.uc_link); 167 } 168