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