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 #include "thr_uberdata.h" 28 #include <procfs.h> 29 #include <ucontext.h> 30 #include <setjmp.h> 31 32 extern int getlwpstatus(thread_t, lwpstatus_t *); 33 extern int putlwpregs(thread_t, prgregset_t); 34 35 void * 36 setup_top_frame(void *stk, size_t stksize, ulwp_t *ulwp) 37 { 38 uint32_t *stack; 39 struct { 40 uint32_t rpc; 41 uint32_t arg; 42 uint32_t fp; 43 uint32_t pc; 44 } frame; 45 46 /* 47 * Top-of-stack must be rounded down to STACK_ALIGN and 48 * there must be a minimum frame. 49 */ 50 stack = (uint32_t *)(((uintptr_t)stk + stksize) & ~(STACK_ALIGN-1)); 51 52 /* 53 * This will return NULL if the kernel cannot allocate 54 * a page for the top page of the stack. This will cause 55 * thr_create(), pthread_create() or pthread_attr_setstack() 56 * to fail, passing the problem up to the application. 57 */ 58 stack -= 4; 59 frame.pc = 0; 60 frame.fp = 0; 61 frame.arg = (uint32_t)ulwp; 62 frame.rpc = (uint32_t)_lwp_start; 63 if (uucopy(&frame, (void *)stack, sizeof (frame)) == 0) 64 return (stack); 65 return (NULL); 66 } 67 68 int 69 setup_context(ucontext_t *ucp, void *(*func)(ulwp_t *), 70 ulwp_t *ulwp, caddr_t stk, size_t stksize) 71 { 72 static int initialized; 73 static greg_t fs, es, ds, cs, ss; 74 75 uint32_t *stack; 76 77 if (!initialized) { 78 ucontext_t uc; 79 80 /* do this once to load the segment registers */ 81 uc.uc_flags = UC_CPU; 82 (void) __getcontext(&uc); 83 fs = uc.uc_mcontext.gregs[FS]; 84 es = uc.uc_mcontext.gregs[ES]; 85 ds = uc.uc_mcontext.gregs[DS]; 86 cs = uc.uc_mcontext.gregs[CS]; 87 ss = uc.uc_mcontext.gregs[SS]; 88 initialized = 1; 89 } 90 /* clear the context and set the segment registers */ 91 (void) memset(ucp, 0, sizeof (*ucp)); 92 ucp->uc_mcontext.gregs[FS] = fs; 93 ucp->uc_mcontext.gregs[ES] = es; 94 ucp->uc_mcontext.gregs[DS] = ds; 95 ucp->uc_mcontext.gregs[CS] = cs; 96 ucp->uc_mcontext.gregs[SS] = ss; 97 98 /* 99 * Yuck. 100 * Use unused kernel pointer field in ucontext 101 * to pass down self pointer and set %gs selector 102 * value so __lwp_create() can setup %gs atomically. 103 * Without this we would need to block all signals 104 * and directly call ___lwp_private() in _thrp_setup 105 * on the other side of __lwp_create(). 106 */ 107 ucp->uc_mcontext.gregs[ESP] = (greg_t)ulwp; 108 ucp->uc_mcontext.gregs[GS] = (greg_t)LWPGS_SEL; 109 110 /* 111 * Setup the top stack frame. 112 * If this fails, pass the problem up to the application. 113 */ 114 if ((stack = setup_top_frame(stk, stksize, ulwp)) == NULL) 115 return (ENOMEM); 116 117 /* fill in registers of interest */ 118 ucp->uc_flags |= UC_CPU; 119 ucp->uc_mcontext.gregs[EIP] = (greg_t)func; 120 ucp->uc_mcontext.gregs[UESP] = (greg_t)stack; 121 ucp->uc_mcontext.gregs[EBP] = (greg_t)(stack + 2); 122 123 return (0); 124 } 125 126 /* 127 * Machine-dependent startup code for a newly-created thread. 128 */ 129 void * 130 _thrp_setup(ulwp_t *self) 131 { 132 self->ul_ustack.ss_sp = (void *)(self->ul_stktop - self->ul_stksiz); 133 self->ul_ustack.ss_size = self->ul_stksiz; 134 self->ul_ustack.ss_flags = 0; 135 (void) setustack(&self->ul_ustack); 136 137 update_sched(self); 138 tls_setup(); 139 140 /* signals have been deferred until now */ 141 sigon(self); 142 143 if (self->ul_cancel_pending == 2 && !self->ul_cancel_disabled) 144 return (NULL); /* cancelled by pthread_create() */ 145 return (self->ul_startpc(self->ul_startarg)); 146 } 147 148 void 149 _fpinherit(ulwp_t *ulwp) 150 { 151 ulwp->ul_fpuenv.ftag = 0xffffffff; 152 } 153 154 void 155 getgregs(ulwp_t *ulwp, gregset_t rs) 156 { 157 lwpstatus_t status; 158 159 if (getlwpstatus(ulwp->ul_lwpid, &status) == 0) { 160 rs[EIP] = status.pr_reg[EIP]; 161 rs[EDI] = status.pr_reg[EDI]; 162 rs[ESI] = status.pr_reg[ESI]; 163 rs[EBP] = status.pr_reg[EBP]; 164 rs[EBX] = status.pr_reg[EBX]; 165 rs[UESP] = status.pr_reg[UESP]; 166 } else { 167 rs[EIP] = 0; 168 rs[EDI] = 0; 169 rs[ESI] = 0; 170 rs[EBP] = 0; 171 rs[EBX] = 0; 172 rs[UESP] = 0; 173 } 174 } 175 176 void 177 setgregs(ulwp_t *ulwp, gregset_t rs) 178 { 179 lwpstatus_t status; 180 181 if (getlwpstatus(ulwp->ul_lwpid, &status) == 0) { 182 status.pr_reg[EIP] = rs[EIP]; 183 status.pr_reg[EDI] = rs[EDI]; 184 status.pr_reg[ESI] = rs[ESI]; 185 status.pr_reg[EBP] = rs[EBP]; 186 status.pr_reg[EBX] = rs[EBX]; 187 status.pr_reg[UESP] = rs[UESP]; 188 (void) putlwpregs(ulwp->ul_lwpid, status.pr_reg); 189 } 190 } 191 192 int 193 __csigsetjmp(greg_t cs, greg_t ss, greg_t gs, 194 greg_t fs, greg_t es, greg_t ds, 195 greg_t edi, greg_t esi, greg_t ebp, greg_t esp, 196 greg_t ebx, greg_t edx, greg_t ecx, greg_t eax, greg_t eip, 197 sigjmp_buf env, int savemask) 198 { 199 ucontext_t *ucp = (ucontext_t *)env; 200 ulwp_t *self = curthread; 201 202 ucp->uc_link = self->ul_siglink; 203 if (self->ul_ustack.ss_flags & SS_ONSTACK) 204 ucp->uc_stack = self->ul_ustack; 205 else { 206 ucp->uc_stack.ss_sp = 207 (void *)(self->ul_stktop - self->ul_stksiz); 208 ucp->uc_stack.ss_size = self->ul_stksiz; 209 ucp->uc_stack.ss_flags = 0; 210 } 211 ucp->uc_flags = UC_STACK | UC_CPU; 212 if (savemask) { 213 ucp->uc_flags |= UC_SIGMASK; 214 enter_critical(self); 215 ucp->uc_sigmask = self->ul_sigmask; 216 exit_critical(self); 217 } 218 ucp->uc_mcontext.gregs[GS] = gs; 219 ucp->uc_mcontext.gregs[FS] = fs; 220 ucp->uc_mcontext.gregs[ES] = es; 221 ucp->uc_mcontext.gregs[DS] = ds; 222 ucp->uc_mcontext.gregs[EDI] = edi; 223 ucp->uc_mcontext.gregs[ESI] = esi; 224 ucp->uc_mcontext.gregs[EBP] = ebp; 225 ucp->uc_mcontext.gregs[ESP] = esp + 4; 226 ucp->uc_mcontext.gregs[EBX] = ebx; 227 ucp->uc_mcontext.gregs[EDX] = edx; 228 ucp->uc_mcontext.gregs[ECX] = ecx; 229 ucp->uc_mcontext.gregs[EAX] = eax; 230 ucp->uc_mcontext.gregs[TRAPNO] = 0; 231 ucp->uc_mcontext.gregs[ERR] = 0; 232 ucp->uc_mcontext.gregs[EIP] = eip; 233 ucp->uc_mcontext.gregs[CS] = cs; 234 ucp->uc_mcontext.gregs[EFL] = 0; 235 ucp->uc_mcontext.gregs[UESP] = esp + 4; 236 ucp->uc_mcontext.gregs[SS] = ss; 237 238 return (0); 239 } 240