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