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 2005 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_syscall(&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 ulwp->ul_gs = LWPGS_SEL; 78 ucp->uc_mcontext.gregs[GS] = (greg_t)ulwp->ul_gs; 79 80 /* top-of-stack must be rounded down to STACK_ALIGN */ 81 stack = (uint32_t *)(((uintptr_t)stk + stksize) & ~(STACK_ALIGN-1)); 82 83 /* set up top stack frame */ 84 *--stack = 0; 85 *--stack = 0; 86 *--stack = (uint32_t)ulwp; 87 *--stack = (uint32_t)_lwp_start; 88 89 /* fill in registers of interest */ 90 ucp->uc_flags |= UC_CPU; 91 ucp->uc_mcontext.gregs[EIP] = (greg_t)func; 92 ucp->uc_mcontext.gregs[UESP] = (greg_t)stack; 93 ucp->uc_mcontext.gregs[EBP] = (greg_t)(stack+2); 94 95 return (0); 96 } 97 98 /* 99 * Machine-dependent startup code for a newly-created thread. 100 */ 101 void * 102 _thr_setup(ulwp_t *self) 103 { 104 self->ul_ustack.ss_sp = (void *)(self->ul_stktop - self->ul_stksiz); 105 self->ul_ustack.ss_size = self->ul_stksiz; 106 self->ul_ustack.ss_flags = 0; 107 (void) _private_setustack(&self->ul_ustack); 108 109 tls_setup(); 110 111 /* signals have been deferred until now */ 112 sigon(self); 113 114 return (self->ul_startpc(self->ul_startarg)); 115 } 116 117 void 118 _fpinherit(ulwp_t *ulwp) 119 { 120 ulwp->ul_fpuenv.ftag = 0xffffffff; 121 } 122 123 void 124 getgregs(ulwp_t *ulwp, gregset_t rs) 125 { 126 lwpstatus_t status; 127 128 if (getlwpstatus(ulwp->ul_lwpid, &status) == 0) { 129 rs[EIP] = status.pr_reg[EIP]; 130 rs[EDI] = status.pr_reg[EDI]; 131 rs[ESI] = status.pr_reg[ESI]; 132 rs[EBP] = status.pr_reg[EBP]; 133 rs[EBX] = status.pr_reg[EBX]; 134 rs[UESP] = status.pr_reg[UESP]; 135 } else { 136 rs[EIP] = 0; 137 rs[EDI] = 0; 138 rs[ESI] = 0; 139 rs[EBP] = 0; 140 rs[EBX] = 0; 141 rs[UESP] = 0; 142 } 143 } 144 145 void 146 setgregs(ulwp_t *ulwp, gregset_t rs) 147 { 148 lwpstatus_t status; 149 150 if (getlwpstatus(ulwp->ul_lwpid, &status) == 0) { 151 status.pr_reg[EIP] = rs[EIP]; 152 status.pr_reg[EDI] = rs[EDI]; 153 status.pr_reg[ESI] = rs[ESI]; 154 status.pr_reg[EBP] = rs[EBP]; 155 status.pr_reg[EBX] = rs[EBX]; 156 status.pr_reg[UESP] = rs[UESP]; 157 (void) putlwpregs(ulwp->ul_lwpid, status.pr_reg); 158 } 159 } 160 161 int 162 __csigsetjmp(greg_t cs, greg_t ss, greg_t gs, 163 greg_t fs, greg_t es, greg_t ds, 164 greg_t edi, greg_t esi, greg_t ebp, greg_t esp, 165 greg_t ebx, greg_t edx, greg_t ecx, greg_t eax, greg_t eip, 166 sigjmp_buf env, int savemask) 167 { 168 ucontext_t *ucp = (ucontext_t *)env; 169 ulwp_t *self = curthread; 170 171 ucp->uc_link = self->ul_siglink; 172 if (self->ul_ustack.ss_flags & SS_ONSTACK) 173 ucp->uc_stack = self->ul_ustack; 174 else { 175 ucp->uc_stack.ss_sp = 176 (void *)(self->ul_stktop - self->ul_stksiz); 177 ucp->uc_stack.ss_size = self->ul_stksiz; 178 ucp->uc_stack.ss_flags = 0; 179 } 180 ucp->uc_flags = UC_STACK | UC_CPU; 181 if (savemask) { 182 ucp->uc_flags |= UC_SIGMASK; 183 enter_critical(self); 184 ucp->uc_sigmask = self->ul_sigmask; 185 exit_critical(self); 186 } 187 ucp->uc_mcontext.gregs[GS] = gs; 188 ucp->uc_mcontext.gregs[FS] = fs; 189 ucp->uc_mcontext.gregs[ES] = es; 190 ucp->uc_mcontext.gregs[DS] = ds; 191 ucp->uc_mcontext.gregs[EDI] = edi; 192 ucp->uc_mcontext.gregs[ESI] = esi; 193 ucp->uc_mcontext.gregs[EBP] = ebp; 194 ucp->uc_mcontext.gregs[ESP] = esp + 4; 195 ucp->uc_mcontext.gregs[EBX] = ebx; 196 ucp->uc_mcontext.gregs[EDX] = edx; 197 ucp->uc_mcontext.gregs[ECX] = ecx; 198 ucp->uc_mcontext.gregs[EAX] = eax; 199 ucp->uc_mcontext.gregs[TRAPNO] = 0; 200 ucp->uc_mcontext.gregs[ERR] = 0; 201 ucp->uc_mcontext.gregs[EIP] = eip; 202 ucp->uc_mcontext.gregs[CS] = cs; 203 ucp->uc_mcontext.gregs[EFL] = 0; 204 ucp->uc_mcontext.gregs[UESP] = esp + 4; 205 ucp->uc_mcontext.gregs[SS] = ss; 206 207 return (0); 208 } 209