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