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