xref: /illumos-gate/usr/src/lib/libc/amd64/threads/machdep.c (revision dd72704bd9e794056c558153663c739e2012d721)
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) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include "lint.h"
27 #include "thr_uberdata.h"
28 #include <procfs.h>
29 #include <ucontext.h>
30 #include <setjmp.h>
31 #include "sigjmp_struct.h"
32 
33 extern int getlwpstatus(thread_t, lwpstatus_t *);
34 extern int putlwpregs(thread_t, prgregset_t);
35 
36 void *
37 setup_top_frame(void *stk, size_t stksize, ulwp_t *ulwp __unused)
38 {
39 	uint64_t *stack;
40 	struct {
41 		uint64_t	rpc;
42 		uint64_t	fp;
43 		uint64_t	pc;
44 	} frame;
45 
46 	/*
47 	 * Top-of-stack must be rounded down to STACK_ALIGN and
48 	 * there must be a minimum frame.
49 	 */
50 	stack = (uint64_t *)(((uintptr_t)stk + stksize) & ~(STACK_ALIGN-1));
51 
52 	/*
53 	 * This will return NULL if the kernel cannot allocate
54 	 * a page for the top page of the stack.  This will cause
55 	 * thr_create(), pthread_create() or pthread_attr_setstack()
56 	 * to fail, passing the problem up to the application.
57 	 */
58 	stack -= 3;
59 	frame.pc = 0;
60 	frame.fp = 0;
61 	frame.rpc = (uint64_t)_lwp_start;
62 	if (uucopy(&frame, stack, sizeof (frame)) == 0)
63 		return (stack);
64 	return (NULL);
65 }
66 
67 int
68 setup_context(ucontext_t *ucp, void *(*func)(ulwp_t *),
69     ulwp_t *ulwp, caddr_t stk, size_t stksize)
70 {
71 	uint64_t *stack;
72 
73 	/* clear the context */
74 	(void) memset(ucp, 0, sizeof (*ucp));
75 
76 	/* setup to store the current thread pointer in %fs */
77 	ucp->uc_mcontext.gregs[REG_FSBASE] = (greg_t)ulwp;
78 	ucp->uc_mcontext.gregs[REG_FS] = 0; /* null selector indicates fsbase */
79 
80 	/* all contexts should have a valid data segment descriptor for %ss */
81 	ucp->uc_mcontext.gregs[REG_SS] = UDS_SEL;
82 
83 	/*
84 	 * Setup the top stack frame.
85 	 * If this fails, pass the problem up to the application.
86 	 */
87 	if ((stack = setup_top_frame(stk, stksize, ulwp)) == NULL)
88 		return (ENOMEM);
89 
90 	/* fill in registers of interest */
91 	ucp->uc_flags |= UC_CPU;
92 	ucp->uc_mcontext.gregs[REG_RDI] = (greg_t)ulwp;
93 	ucp->uc_mcontext.gregs[REG_RIP] = (greg_t)func;
94 	ucp->uc_mcontext.gregs[REG_RSP] = (greg_t)stack;
95 	ucp->uc_mcontext.gregs[REG_RBP] = (greg_t)(stack + 1);
96 
97 	return (0);
98 }
99 
100 /*
101  * Machine-dependent startup code for a newly-created thread.
102  */
103 void *
104 _thrp_setup(ulwp_t *self)
105 {
106 	self->ul_ustack.ss_sp = (void *)(self->ul_stktop - self->ul_stksiz);
107 	self->ul_ustack.ss_size = self->ul_stksiz;
108 	self->ul_ustack.ss_flags = 0;
109 	(void) setustack(&self->ul_ustack);
110 
111 	update_sched(self);
112 	tls_setup();
113 
114 	/* signals have been deferred until now */
115 	sigon(self);
116 
117 	if (self->ul_cancel_pending == 2 && !self->ul_cancel_disabled)
118 		return (NULL);	/* cancelled by pthread_create() */
119 	return (self->ul_startpc(self->ul_startarg));
120 }
121 
122 void
123 _fpinherit(ulwp_t *ulwp)
124 {
125 	ulwp->ul_fpuenv.ftag = 0xffffffff;
126 }
127 
128 void
129 getgregs(ulwp_t *ulwp, gregset_t rs)
130 {
131 	lwpstatus_t status;
132 
133 	if (getlwpstatus(ulwp->ul_lwpid, &status) == 0) {
134 		rs[REG_RBX] = status.pr_reg[REG_RBX];
135 		rs[REG_R12] = status.pr_reg[REG_R12];
136 		rs[REG_R13] = status.pr_reg[REG_R13];
137 		rs[REG_R14] = status.pr_reg[REG_R14];
138 		rs[REG_R15] = status.pr_reg[REG_R15];
139 		rs[REG_RBP] = status.pr_reg[REG_RBP];
140 		rs[REG_RSP] = status.pr_reg[REG_RSP];
141 		rs[REG_RIP] = status.pr_reg[REG_RIP];
142 	} else {
143 		rs[REG_RBX] = 0;
144 		rs[REG_R12] = 0;
145 		rs[REG_R13] = 0;
146 		rs[REG_R14] = 0;
147 		rs[REG_R15] = 0;
148 		rs[REG_RBP] = 0;
149 		rs[REG_RSP] = 0;
150 		rs[REG_RIP] = 0;
151 	}
152 }
153 
154 void
155 setgregs(ulwp_t *ulwp, gregset_t rs)
156 {
157 	lwpstatus_t status;
158 
159 	if (getlwpstatus(ulwp->ul_lwpid, &status) == 0) {
160 		status.pr_reg[REG_RBX] = rs[REG_RBX];
161 		status.pr_reg[REG_R12] = rs[REG_R12];
162 		status.pr_reg[REG_R13] = rs[REG_R13];
163 		status.pr_reg[REG_R14] = rs[REG_R14];
164 		status.pr_reg[REG_R15] = rs[REG_R15];
165 		status.pr_reg[REG_RBP] = rs[REG_RBP];
166 		status.pr_reg[REG_RSP] = rs[REG_RSP];
167 		status.pr_reg[REG_RIP] = rs[REG_RIP];
168 		(void) putlwpregs(ulwp->ul_lwpid, status.pr_reg);
169 	}
170 }
171 
172 int
173 __csigsetjmp(sigjmp_buf env, int savemask, gregset_t rs)
174 {
175 	ucontext_t *ucp = SIGJMP2UCONTEXT(env);
176 	ulwp_t *self = curthread;
177 
178 	ucp->uc_link = self->ul_siglink;
179 	if (self->ul_ustack.ss_flags & SS_ONSTACK)
180 		ucp->uc_stack = self->ul_ustack;
181 	else {
182 		ucp->uc_stack.ss_sp =
183 		    (void *)(self->ul_stktop - self->ul_stksiz);
184 		ucp->uc_stack.ss_size = self->ul_stksiz;
185 		ucp->uc_stack.ss_flags = 0;
186 	}
187 	ucp->uc_flags = UC_STACK | UC_CPU;
188 	if (savemask) {
189 		ucp->uc_flags |= UC_SIGMASK;
190 		enter_critical(self);
191 		ucp->uc_sigmask = self->ul_sigmask;
192 		exit_critical(self);
193 	}
194 	(void) memcpy(ucp->uc_mcontext.gregs, rs, _NGREG * sizeof (greg_t));
195 
196 	return (0);
197 }
198 
199 void
200 smt_pause(void)
201 {
202 	SMT_PAUSE();
203 }
204