1/* Create new context.
2   Copyright (C) 2001-2022 Free Software Foundation, Inc.
3   This file is part of the GNU C Library.
4
5   The GNU C Library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9
10   The GNU C Library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14
15   You should have received a copy of the GNU Lesser General Public
16   License along with the GNU C Library; if not, see
17   <https://www.gnu.org/licenses/>.  */
18
19#include <sysdep.h>
20#include <asm/prctl.h>
21
22#include "ucontext_i.h"
23
24
25ENTRY(__makecontext)
26	movl	4(%esp), %eax
27
28	/* Load the address of the function we are supposed to run.  */
29	movl	8(%esp), %ecx
30
31	/* Compute the address of the stack.  The information comes from
32	   to us_stack element.  */
33	movl	oSS_SP(%eax), %edx
34	movl	%ecx, oEIP(%eax)
35	addl	oSS_SIZE(%eax), %edx
36
37	/* Remember the number of parameters for the exit handler since
38	   it has to remove them.  We store the number in the EBX register
39	   which the function we will call must preserve.  */
40	movl	12(%esp), %ecx
41	movl	%ecx, oEBX(%eax)
42
43	/* Make room on the new stack for the parameters.
44	   Room for the arguments, return address (== L(exitcode)) and
45	   oLINK pointer is needed.  One of the pointer sizes is subtracted
46	   after aligning the stack.  */
47	negl	%ecx
48	leal	-4(%edx,%ecx,4), %edx
49	negl	%ecx
50
51	/* Align the stack.  */
52	andl	$0xfffffff0, %edx
53	subl	$4, %edx
54
55	/* Store the future stack pointer.  */
56	movl	%edx, oESP(%eax)
57
58	/* Put the next context on the new stack (from the uc_link
59	   element).  */
60	movl	oLINK(%eax), %eax
61	movl	%eax, 4(%edx,%ecx,4)
62
63	/* Copy all the parameters.  */
64	jecxz	2f
651:	movl	12(%esp,%ecx,4), %eax
66	movl	%eax, (%edx,%ecx,4)
67	decl	%ecx
68	jnz	1b
692:
70
71#if SHSTK_ENABLED
72	/* Check if Shadow Stack is enabled.  */
73	testl	$X86_FEATURE_1_SHSTK, %gs:FEATURE_1_OFFSET
74	jz	L(skip_ssp)
75
76	/* Reload the pointer to ucontext.  */
77	movl	4(%esp), %eax
78
79	/* Shadow stack is enabled.  We need to allocate a new shadow
80	   stack.  */
81	subl	oSS_SP(%eax), %edx
82	shrl	$STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT, %edx
83
84	/* Align shadow stack size to 8 bytes.  */
85	addl	$7, %edx
86	andl	$-8, %edx
87
88	/* Store shadow stack size in __ssp[2].  */
89	movl	%edx, (oSSP + 8)(%eax)
90
91	/* Save ESI in the second scratch register slot.  */
92	movl	%esi, oSCRATCH2(%eax)
93	/* Save EDI in the third scratch register slot.  */
94	movl	%edi, oSCRATCH3(%eax)
95
96	/* Save the pointer to ucontext.  */
97	movl	%eax, %edi
98
99	/* Get the original shadow stack pointer.  */
100	rdsspd	%esi
101
102	/* Align the saved original shadow stack pointer to the next
103	   8 byte aligned boundary.  */
104	andl	$-8, %esi
105
106	/* Load the top of the new stack into EDX.  */
107	movl	oESP(%eax), %edx
108
109	/* We need to terminate the FDE here because the unwinder looks
110	   at ra-1 for unwind information.  */
111	cfi_endproc
112
113	/* Swap the original stack pointer with the top of the new
114	   stack.  */
115	xchgl	%esp, %edx
116
117	/* Add 4 bytes since CALL will push the 4-byte return address
118	   onto stack.  */
119	addl	$4, %esp
120
121	/* Allocate the new shadow stack.  Save EBX in the first scratch
122	   register slot.  */
123	movl	%ebx, oSCRATCH1(%eax)
124
125	/* CET syscall takes 64-bit sizes.  */
126	subl	$16, %esp
127	movl	(oSSP + 8)(%eax), %ecx
128	movl	%ecx, (%esp)
129	movl	$0, 4(%esp)
130	movl	%ecx, 8(%esp)
131	movl	$0, 12(%esp)
132	movl	%esp, %ecx
133
134	movl	$ARCH_CET_ALLOC_SHSTK, %ebx
135	movl	$__NR_arch_prctl, %eax
136	ENTER_KERNEL
137	testl	%eax, %eax
138	jne	L(hlt)		/* This should never happen.  */
139
140	/* Copy the base address of the new shadow stack to __ssp[1].  */
141	movl	(%esp), %eax
142	movl	%eax, (oSSP + 4)(%edi)
143
144	addl	$16, %esp
145
146	/* Restore EBX from the first scratch register slot.  */
147	movl	oSCRATCH1(%edi), %ebx
148
149	/* Get the size of the new shadow stack.  */
150	movl	(oSSP + 8)(%edi), %ecx
151
152	/* Use the restore stoken to restore the new shadow stack.  */
153	rstorssp -8(%eax, %ecx)
154
155	/* Save the restore token at the next 8 byte aligned boundary
156	   on the original shadow stack.  */
157	saveprevssp
158
159	/* Push the address of "jmp exitcode" onto the new stack as
160	   well as the new shadow stack.  */
161	call	1f
162	jmp	L(exitcode)
1631:
164
165	/* Get the new shadow stack pointer.  */
166	rdsspd	%eax
167
168	/* Use the restore stoken to restore the original shadow stack.  */
169	rstorssp -8(%esi)
170
171	/* Save the restore token on the new shadow stack.  */
172	saveprevssp
173
174	/* Store the new shadow stack pointer in __ssp[0].  */
175	movl	%eax, oSSP(%edi)
176
177	/* Restore the original stack.  */
178	mov	%edx, %esp
179
180	cfi_startproc
181
182	/* Restore ESI from the second scratch register slot.  */
183	movl	oSCRATCH2(%edi), %esi
184	/* Restore EDI from the third scratch register slot.  */
185	movl	oSCRATCH3(%edi), %edi
186
187	ret
188
189L(skip_ssp):
190#endif
191
192	/* If the function we call returns we must continue with the
193	   context which is given in the uc_link element.  To do this
194	   set the return address for the function the user provides
195	   to a little bit of helper code which does the magic (see
196	   below).  */
197#ifdef PIC
198	call	1f
199	cfi_adjust_cfa_offset (4)
2001:	popl	%ecx
201	cfi_adjust_cfa_offset (-4)
202	addl	$L(exitcode)-1b, %ecx
203	movl	%ecx, (%edx)
204#else
205	movl	$L(exitcode), (%edx)
206#endif
207	/* We need to terminate the FDE here instead of after ret because
208	   the unwinder looks at ra-1 for unwind information.  */
209	cfi_endproc
210
211	/* 'makecontext' returns no value.  */
212	ret
213
214	/* This is the helper code which gets called if a function which
215	   is registered with 'makecontext' returns.  In this case we
216	   have to install the context listed in the uc_link element of
217	   the context 'makecontext' manipulated at the time of the
218	   'makecontext' call.  If the pointer is NULL the process must
219	   terminate.  */
220L(exitcode):
221	/* This removes the parameters passed to the function given to
222	   'makecontext' from the stack.  EBX contains the number of
223	   parameters (see above).  */
224	leal	(%esp,%ebx,4), %esp
225
226	cmpl	$0, (%esp)		/* Check the next context.  */
227	je	2f			/* If it is zero exit.  */
228
229	call	HIDDEN_JUMPTARGET(__setcontext)
230	/* If this returns (which can happen if the syscall fails) we'll
231	   exit the program with the return error value (-1).  */
232	jmp L(call_exit)
233
2342:
235	/* Exit with status 0.  */
236	xorl	%eax, %eax
237
238L(call_exit):
239	/* Align the stack and pass the exit code (from %eax).  */
240	andl	$0xfffffff0, %esp
241	subl	$12, %esp
242	pushl	%eax
243
244	call	HIDDEN_JUMPTARGET(exit)
245	/* The 'exit' call should never return.  In case it does cause
246	   the process to terminate.  */
247L(hlt):
248	hlt
249	cfi_startproc
250END(__makecontext)
251
252weak_alias (__makecontext, makecontext)
253