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.
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.
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]
23 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include "thr_uberdata.h"
32 * The stack needs to be 16-byte aligned with a 4-byte bias. See comment in
33 * lib/libc/i386/gen/makectxt.c.
35 * Note: If you change it, you need to change it in the following files as
38 * - lib/libc/i386/gen/makectxt.c
39 * - lib/common/i386/crti.s
40 * - lib/common/i386/crt1.s
43 #define STACK_ALIGN 16
45 extern int getlwpstatus(thread_t
, lwpstatus_t
*);
46 extern int putlwpregs(thread_t
, prgregset_t
);
49 setup_top_frame(void *stk
, size_t stksize
, ulwp_t
*ulwp
)
61 * Top-of-stack must be rounded down to STACK_ALIGN and
62 * there must be a minimum frame. Note: 'frame' is not a true
63 * stack frame (see <sys/frame.h>) but a construction made here to
64 * make it look like _lwp_start called the thread start function
65 * with a 16-byte aligned stack pointer (the address of frame.arg
66 * is the address that muet be aligned on a 16-byte boundary).
68 stack
= (uint32_t *)(((uintptr_t)stk
+ stksize
) & ~(STACK_ALIGN
-1));
71 * This will return NULL if the kernel cannot allocate
72 * a page for the top page of the stack. This will cause
73 * thr_create(), pthread_create() or pthread_attr_setstack()
74 * to fail, passing the problem up to the application.
76 stack
-= 5; /* make the address of frame.arg be 16-byte aligned */
78 frame
.fp
= 0; /* initial address for %ebp (see EBP below) */
80 frame
.arg
= (uint32_t)ulwp
;
81 frame
.rpc
= (uint32_t)_lwp_start
;
82 if (uucopy(&frame
, (void *)stack
, sizeof (frame
)) == 0)
88 setup_context(ucontext_t
*ucp
, void *(*func
)(ulwp_t
*),
89 ulwp_t
*ulwp
, caddr_t stk
, size_t stksize
)
91 static int initialized
;
92 static greg_t fs
, es
, ds
, cs
, ss
;
99 /* do this once to load the segment registers */
100 uc
.uc_flags
= UC_CPU
;
101 (void) __getcontext(&uc
);
102 fs
= uc
.uc_mcontext
.gregs
[FS
];
103 es
= uc
.uc_mcontext
.gregs
[ES
];
104 ds
= uc
.uc_mcontext
.gregs
[DS
];
105 cs
= uc
.uc_mcontext
.gregs
[CS
];
106 ss
= uc
.uc_mcontext
.gregs
[SS
];
109 /* clear the context and set the segment registers */
110 (void) memset(ucp
, 0, sizeof (*ucp
));
111 ucp
->uc_mcontext
.gregs
[FS
] = fs
;
112 ucp
->uc_mcontext
.gregs
[ES
] = es
;
113 ucp
->uc_mcontext
.gregs
[DS
] = ds
;
114 ucp
->uc_mcontext
.gregs
[CS
] = cs
;
115 ucp
->uc_mcontext
.gregs
[SS
] = ss
;
119 * Use unused kernel pointer field in ucontext
120 * to pass down self pointer and set %gs selector
121 * value so __lwp_create() can setup %gs atomically.
122 * Without this we would need to block all signals
123 * and directly call ___lwp_private() in _thrp_setup
124 * on the other side of __lwp_create().
126 ucp
->uc_mcontext
.gregs
[ESP
] = (greg_t
)ulwp
;
127 ucp
->uc_mcontext
.gregs
[GS
] = (greg_t
)LWPGS_SEL
;
130 * Setup the top stack frame.
131 * If this fails, pass the problem up to the application.
133 if ((stack
= setup_top_frame(stk
, stksize
, ulwp
)) == NULL
)
136 /* fill in registers of interest */
137 ucp
->uc_flags
|= UC_CPU
;
138 ucp
->uc_mcontext
.gregs
[EIP
] = (greg_t
)func
;
139 ucp
->uc_mcontext
.gregs
[UESP
] = (greg_t
)stack
;
140 ucp
->uc_mcontext
.gregs
[EBP
] = (greg_t
)(stack
+ 3);
146 * Machine-dependent startup code for a newly-created thread.
149 _thrp_setup(ulwp_t
*self
)
151 self
->ul_ustack
.ss_sp
= (void *)(self
->ul_stktop
- self
->ul_stksiz
);
152 self
->ul_ustack
.ss_size
= self
->ul_stksiz
;
153 self
->ul_ustack
.ss_flags
= 0;
154 (void) setustack(&self
->ul_ustack
);
159 /* signals have been deferred until now */
162 if (self
->ul_cancel_pending
== 2 && !self
->ul_cancel_disabled
)
163 return (NULL
); /* cancelled by pthread_create() */
164 return (self
->ul_startpc(self
->ul_startarg
));
168 _fpinherit(ulwp_t
*ulwp
)
170 ulwp
->ul_fpuenv
.ftag
= 0xffffffff;
174 getgregs(ulwp_t
*ulwp
, gregset_t rs
)
178 if (getlwpstatus(ulwp
->ul_lwpid
, &status
) == 0) {
179 rs
[EIP
] = status
.pr_reg
[EIP
];
180 rs
[EDI
] = status
.pr_reg
[EDI
];
181 rs
[ESI
] = status
.pr_reg
[ESI
];
182 rs
[EBP
] = status
.pr_reg
[EBP
];
183 rs
[EBX
] = status
.pr_reg
[EBX
];
184 rs
[UESP
] = status
.pr_reg
[UESP
];
196 setgregs(ulwp_t
*ulwp
, gregset_t rs
)
200 if (getlwpstatus(ulwp
->ul_lwpid
, &status
) == 0) {
201 status
.pr_reg
[EIP
] = rs
[EIP
];
202 status
.pr_reg
[EDI
] = rs
[EDI
];
203 status
.pr_reg
[ESI
] = rs
[ESI
];
204 status
.pr_reg
[EBP
] = rs
[EBP
];
205 status
.pr_reg
[EBX
] = rs
[EBX
];
206 status
.pr_reg
[UESP
] = rs
[UESP
];
207 (void) putlwpregs(ulwp
->ul_lwpid
, status
.pr_reg
);
212 __csigsetjmp(greg_t cs
, greg_t ss
, greg_t gs
,
213 greg_t fs
, greg_t es
, greg_t ds
,
214 greg_t edi
, greg_t esi
, greg_t ebp
, greg_t esp
,
215 greg_t ebx
, greg_t edx
, greg_t ecx
, greg_t eax
, greg_t eip
,
216 sigjmp_buf env
, int savemask
)
218 ucontext_t
*ucp
= (ucontext_t
*)env
;
219 ulwp_t
*self
= curthread
;
221 ucp
->uc_link
= self
->ul_siglink
;
222 if (self
->ul_ustack
.ss_flags
& SS_ONSTACK
)
223 ucp
->uc_stack
= self
->ul_ustack
;
225 ucp
->uc_stack
.ss_sp
=
226 (void *)(self
->ul_stktop
- self
->ul_stksiz
);
227 ucp
->uc_stack
.ss_size
= self
->ul_stksiz
;
228 ucp
->uc_stack
.ss_flags
= 0;
230 ucp
->uc_flags
= UC_STACK
| UC_CPU
;
232 ucp
->uc_flags
|= UC_SIGMASK
;
233 enter_critical(self
);
234 ucp
->uc_sigmask
= self
->ul_sigmask
;
237 ucp
->uc_mcontext
.gregs
[GS
] = gs
;
238 ucp
->uc_mcontext
.gregs
[FS
] = fs
;
239 ucp
->uc_mcontext
.gregs
[ES
] = es
;
240 ucp
->uc_mcontext
.gregs
[DS
] = ds
;
241 ucp
->uc_mcontext
.gregs
[EDI
] = edi
;
242 ucp
->uc_mcontext
.gregs
[ESI
] = esi
;
243 ucp
->uc_mcontext
.gregs
[EBP
] = ebp
;
244 ucp
->uc_mcontext
.gregs
[ESP
] = esp
+ 4;
245 ucp
->uc_mcontext
.gregs
[EBX
] = ebx
;
246 ucp
->uc_mcontext
.gregs
[EDX
] = edx
;
247 ucp
->uc_mcontext
.gregs
[ECX
] = ecx
;
248 ucp
->uc_mcontext
.gregs
[EAX
] = eax
;
249 ucp
->uc_mcontext
.gregs
[TRAPNO
] = 0;
250 ucp
->uc_mcontext
.gregs
[ERR
] = 0;
251 ucp
->uc_mcontext
.gregs
[EIP
] = eip
;
252 ucp
->uc_mcontext
.gregs
[CS
] = cs
;
253 ucp
->uc_mcontext
.gregs
[EFL
] = 0;
254 ucp
->uc_mcontext
.gregs
[UESP
] = esp
+ 4;
255 ucp
->uc_mcontext
.gregs
[SS
] = ss
;