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 "lint.h" 30 #include "thr_uberdata.h" 31 #include <procfs.h> 32 #include <setjmp.h> 33 #include <sys/fsr.h> 34 #include "sigjmp_struct.h" 35 36 extern int getlwpstatus(thread_t, lwpstatus_t *); 37 extern int putlwpregs(thread_t, prgregset_t); 38 39 int 40 setup_context(ucontext_t *ucp, void *(*func)(ulwp_t *), 41 ulwp_t *ulwp, caddr_t stk, size_t stksize) 42 { 43 /* 44 * Top-of-stack must be rounded down to STACK_ALIGN and 45 * there must be a minimum frame for the register window. 46 */ 47 uintptr_t stack = (((uintptr_t)stk + stksize) & ~(STACK_ALIGN - 1)) - 48 SA(MINFRAME); 49 50 /* clear the context and the top stack frame */ 51 (void) _memset(ucp, 0, sizeof (*ucp)); 52 (void) _memset((void *)stack, 0, SA(MINFRAME)); 53 54 /* fill in registers of interest */ 55 ucp->uc_flags |= UC_CPU; 56 ucp->uc_mcontext.gregs[REG_PC] = (greg_t)func; 57 ucp->uc_mcontext.gregs[REG_nPC] = (greg_t)func + 4; 58 ucp->uc_mcontext.gregs[REG_O0] = (greg_t)ulwp; 59 ucp->uc_mcontext.gregs[REG_SP] = (greg_t)(stack - STACK_BIAS); 60 ucp->uc_mcontext.gregs[REG_O7] = (greg_t)_lwp_start; 61 ucp->uc_mcontext.gregs[REG_G7] = (greg_t)ulwp; 62 63 return (0); 64 } 65 66 /* 67 * Machine-dependent startup code for a newly-created thread. 68 */ 69 void * 70 _thr_setup(ulwp_t *self) 71 { 72 extern void _setfsr(greg_t *); 73 74 if (self->ul_fpuenv.fpu_en) 75 _setfsr(&self->ul_fpuenv.fsr); 76 77 self->ul_ustack.ss_sp = (void *)(self->ul_stktop - self->ul_stksiz); 78 self->ul_ustack.ss_size = self->ul_stksiz; 79 self->ul_ustack.ss_flags = 0; 80 (void) _private_setustack(&self->ul_ustack); 81 tls_setup(); 82 83 /* signals have been deferred until now */ 84 sigon(self); 85 86 return (self->ul_startpc(self->ul_startarg)); 87 } 88 89 void 90 _fpinherit(ulwp_t *ulwp) 91 { 92 extern void _getfsr(greg_t *); 93 int fpu_enabled; 94 95 #ifdef __sparcv9 96 extern greg_t _getfprs(); 97 fpu_enabled = _getfprs() & FPRS_FEF; 98 #else 99 extern psw_t _getpsr(); 100 fpu_enabled = _getpsr() & PSR_EF; 101 #endif /* __sparcv9 */ 102 103 if (fpu_enabled) { 104 _getfsr(&ulwp->ul_fpuenv.fsr); 105 ulwp->ul_fpuenv.fpu_en = 1; 106 } else { 107 ulwp->ul_fpuenv.fpu_en = 0; 108 } 109 } 110 111 void 112 getgregs(ulwp_t *ulwp, gregset_t rs) 113 { 114 lwpstatus_t status; 115 116 if (getlwpstatus(ulwp->ul_lwpid, &status) == 0) { 117 rs[REG_PC] = status.pr_reg[R_PC]; 118 rs[REG_O6] = status.pr_reg[R_O6]; 119 rs[REG_O7] = status.pr_reg[R_O7]; 120 rs[REG_G1] = status.pr_reg[R_G1]; 121 rs[REG_G2] = status.pr_reg[R_G2]; 122 rs[REG_G3] = status.pr_reg[R_G3]; 123 rs[REG_G4] = status.pr_reg[R_G4]; 124 } else { 125 rs[REG_PC] = 0; 126 rs[REG_O6] = 0; 127 rs[REG_O7] = 0; 128 rs[REG_G1] = 0; 129 rs[REG_G2] = 0; 130 rs[REG_G3] = 0; 131 rs[REG_G4] = 0; 132 } 133 } 134 135 void 136 setgregs(ulwp_t *ulwp, gregset_t rs) 137 { 138 lwpstatus_t status; 139 140 if (getlwpstatus(ulwp->ul_lwpid, &status) == 0) { 141 status.pr_reg[R_PC] = rs[REG_PC]; 142 status.pr_reg[R_O6] = rs[REG_O6]; 143 status.pr_reg[R_O7] = rs[REG_O7]; 144 status.pr_reg[R_G1] = rs[REG_G1]; 145 status.pr_reg[R_G2] = rs[REG_G2]; 146 status.pr_reg[R_G3] = rs[REG_G3]; 147 status.pr_reg[R_G4] = rs[REG_G4]; 148 (void) putlwpregs(ulwp->ul_lwpid, status.pr_reg); 149 } 150 } 151 152 int 153 __csigsetjmp(sigjmp_buf env, int savemask) 154 { 155 sigjmp_struct_t *bp = (sigjmp_struct_t *)env; 156 ulwp_t *self = curthread; 157 158 /* 159 * bp->sjs_sp, bp->sjs_pc, bp->sjs_fp and bp->sjs_i7 are already set. 160 */ 161 bp->sjs_flags = JB_FRAMEPTR; 162 bp->sjs_uclink = self->ul_siglink; 163 if (self->ul_ustack.ss_flags & SS_ONSTACK) 164 bp->sjs_stack = self->ul_ustack; 165 else { 166 bp->sjs_stack.ss_sp = 167 (void *)(self->ul_stktop - self->ul_stksiz); 168 bp->sjs_stack.ss_size = self->ul_stksiz; 169 bp->sjs_stack.ss_flags = 0; 170 } 171 if (savemask) { 172 bp->sjs_flags |= JB_SAVEMASK; 173 enter_critical(self); 174 bp->sjs_sigmask = self->ul_sigmask; 175 exit_critical(self); 176 } 177 178 return (0); 179 } 180