17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
57257d1braf * Common Development and Distribution License (the "License").
67257d1braf * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
217257d1braf
227c478bdstevel@tonic-gate/*
237257d1braf * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bdstevel@tonic-gate * Use is subject to license terms.
257c478bdstevel@tonic-gate */
267c478bdstevel@tonic-gate
277c478bdstevel@tonic-gate/*	Copyright (c) 1988 AT&T	*/
287c478bdstevel@tonic-gate/*	  All Rights Reserved  	*/
297c478bdstevel@tonic-gate
307257d1braf#pragma weak _makecontext = makecontext
317c478bdstevel@tonic-gate
327257d1braf#include "lint.h"
337c478bdstevel@tonic-gate#include <stdarg.h>
347c478bdstevel@tonic-gate#include <ucontext.h>
357c478bdstevel@tonic-gate#include <sys/stack.h>
367c478bdstevel@tonic-gate
377c478bdstevel@tonic-gate/*
387c478bdstevel@tonic-gate * The ucontext_t that the user passes in must have been primed with a
397c478bdstevel@tonic-gate * call to getcontext(2), have the uc_stack member set to reflect the
407c478bdstevel@tonic-gate * stack which this context will use, and have the uc_link member set
417c478bdstevel@tonic-gate * to the context which should be resumed when this context returns.
427c478bdstevel@tonic-gate * When makecontext() returns, the ucontext_t will be set to run the
437c478bdstevel@tonic-gate * given function with the given parameters on the stack specified by
447c478bdstevel@tonic-gate * uc_stack, and which will return to the ucontext_t specified by uc_link.
457c478bdstevel@tonic-gate */
467c478bdstevel@tonic-gate
47ceef08dJosef 'Jeff' Sipek/*
48ceef08dJosef 'Jeff' Sipek * The original i386 ABI said that the stack pointer need be only 4-byte
49ceef08dJosef 'Jeff' Sipek * aligned before a function call (STACK_ALIGN == 4).  The ABI supplement
50ceef08dJosef 'Jeff' Sipek * version 1.0 changed the required alignment to 16-byte for the benefit of
51ceef08dJosef 'Jeff' Sipek * floating point code compiled using sse2.  The compiler assumes this
52ceef08dJosef 'Jeff' Sipek * alignment and maintains it for calls it generates.  If the stack is
53ceef08dJosef 'Jeff' Sipek * initially properly aligned, it will continue to be so aligned.  If it is
54ceef08dJosef 'Jeff' Sipek * not initially so aligned, it will never become so aligned.
55ceef08dJosef 'Jeff' Sipek *
56ceef08dJosef 'Jeff' Sipek * One slightly confusing detail to keep in mind is that the 16-byte
57ceef08dJosef 'Jeff' Sipek * alignment (%esp & 0xf == 0) is true just *before* the call instruction.
58ceef08dJosef 'Jeff' Sipek * The call instruction will then push a return value, decrementing %esp by
59ceef08dJosef 'Jeff' Sipek * 4.  Therefore, if one dumps %esp at the at the very first instruction in
60ceef08dJosef 'Jeff' Sipek * a function, it will end with a 0xc.  The compiler expects this and
61ceef08dJosef 'Jeff' Sipek * compensates for it properly.
62ceef08dJosef 'Jeff' Sipek *
63ceef08dJosef 'Jeff' Sipek * Note: If you change this value, you need to change it in the following
64ceef08dJosef 'Jeff' Sipek * files as well:
65ceef08dJosef 'Jeff' Sipek *
66ceef08dJosef 'Jeff' Sipek *  - lib/libc/i386/threads/machdep.c
673e76f9dRichard Lowe *  - lib/crt/i386/crti.s
683e76f9dRichard Lowe *  - lib/crt/i386/crt1.s
69ceef08dJosef 'Jeff' Sipek */
70ceef08dJosef 'Jeff' Sipek#undef	STACK_ALIGN
71ceef08dJosef 'Jeff' Sipek#define	STACK_ALIGN	16
72ceef08dJosef 'Jeff' Sipek
737c478bdstevel@tonic-gatestatic void resumecontext(void);
747c478bdstevel@tonic-gate
757c478bdstevel@tonic-gatevoid
767c478bdstevel@tonic-gatemakecontext(ucontext_t *ucp, void (*func)(), int argc, ...)
777c478bdstevel@tonic-gate{
787c478bdstevel@tonic-gate	long *sp;
797c478bdstevel@tonic-gate	long *tsp;
807c478bdstevel@tonic-gate	va_list ap;
817c478bdstevel@tonic-gate	size_t size;
827c478bdstevel@tonic-gate
837c478bdstevel@tonic-gate	ucp->uc_mcontext.gregs[EIP] = (greg_t)func;
847c478bdstevel@tonic-gate
857c478bdstevel@tonic-gate	size = sizeof (long) * (argc + 1);
867c478bdstevel@tonic-gate
87ceef08dJosef 'Jeff' Sipek	tsp = (long *)(((uintptr_t)ucp->uc_stack.ss_sp +
887c478bdstevel@tonic-gate	    ucp->uc_stack.ss_size - size) & ~(STACK_ALIGN - 1));
897c478bdstevel@tonic-gate
90ceef08dJosef 'Jeff' Sipek	/*
91ceef08dJosef 'Jeff' Sipek	 * Since we're emulating the call instruction, we must push the
92ceef08dJosef 'Jeff' Sipek	 * return address (which involves adjusting the stack pointer to
93ceef08dJosef 'Jeff' Sipek	 * have the proper 4-byte bias).
94ceef08dJosef 'Jeff' Sipek	 */
95ceef08dJosef 'Jeff' Sipek	sp = tsp - 1;
967c478bdstevel@tonic-gate
977c478bdstevel@tonic-gate	*sp = (long)resumecontext;		/* return address */
987c478bdstevel@tonic-gate
997c478bdstevel@tonic-gate	ucp->uc_mcontext.gregs[UESP] = (greg_t)sp;
100ceef08dJosef 'Jeff' Sipek
101ceef08dJosef 'Jeff' Sipek	/*
102ceef08dJosef 'Jeff' Sipek	 * "push" all the arguments
103ceef08dJosef 'Jeff' Sipek	 */
104ceef08dJosef 'Jeff' Sipek	va_start(ap, argc);
105ceef08dJosef 'Jeff' Sipek	while (argc-- > 0)
106ceef08dJosef 'Jeff' Sipek		*tsp++ = va_arg(ap, long);
107ceef08dJosef 'Jeff' Sipek	va_end(ap);
1087c478bdstevel@tonic-gate}
1097c478bdstevel@tonic-gate
1107c478bdstevel@tonic-gate
1117c478bdstevel@tonic-gatestatic void
1127c478bdstevel@tonic-gateresumecontext(void)
1137c478bdstevel@tonic-gate{
1147c478bdstevel@tonic-gate	ucontext_t uc;
1157c478bdstevel@tonic-gate
1167c478bdstevel@tonic-gate	(void) getcontext(&uc);
1177c478bdstevel@tonic-gate	(void) setcontext(uc.uc_link);
1187c478bdstevel@tonic-gate}
119