Home | History | Annotate | Download | only in gen
      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 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*	Copyright (c) 1988 AT&T	*/
     28 /*	  All Rights Reserved  	*/
     29 
     30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     31 
     32 #pragma weak _makecontext = makecontext
     33 
     34 #include "lint.h"
     35 #include <stdarg.h>
     36 #include <ucontext.h>
     37 #include <sys/stack.h>
     38 
     39 /*
     40  * The ucontext_t that the user passes in must have been primed with a
     41  * call to getcontext(2), have the uc_stack member set to reflect the
     42  * stack which this context will use, and have the uc_link member set
     43  * to the context which should be resumed when this context returns.
     44  * When makecontext() returns, the ucontext_t will be set to run the
     45  * given function with the given parameters on the stack specified by
     46  * uc_stack, and which will return to the ucontext_t specified by uc_link.
     47  */
     48 
     49 static void resumecontext(void);
     50 
     51 void
     52 makecontext(ucontext_t *ucp, void (*func)(), int argc, ...)
     53 {
     54 	long *sp;
     55 	long *tsp;
     56 	va_list ap;
     57 	size_t size;
     58 	int pusharg = (argc > 6 ? argc - 6 : 0);
     59 	greg_t tmp;
     60 	int i;
     61 
     62 	ucp->uc_mcontext.gregs[REG_PC] = (greg_t)func;
     63 
     64 	size = sizeof (long) * (pusharg + 1);
     65 
     66 	/*
     67 	 * Calculate new value for %rsp. On entry to a function,
     68 	 * %rsp must be STACK_ENTRY_ALIGNed but not STACK_ALIGNed.
     69 	 * This is because the pushq %rbp will correct the alignment.
     70 	 */
     71 
     72 	sp = (long *)(((uintptr_t)ucp->uc_stack.ss_sp +
     73 	    ucp->uc_stack.ss_size - size) & ~(STACK_ENTRY_ALIGN - 1));
     74 
     75 	if (((uintptr_t)sp & (STACK_ALIGN - 1ul)) == 0)
     76 		sp -= STACK_ENTRY_ALIGN / sizeof (*sp);
     77 
     78 	tsp = sp + 1;
     79 
     80 	va_start(ap, argc);
     81 
     82 	for (i = 0; i < argc; i++) {
     83 		tmp = va_arg(ap, long);
     84 		switch (i) {
     85 		case 0:
     86 			ucp->uc_mcontext.gregs[REG_RDI] = tmp;
     87 			break;
     88 		case 1:
     89 			ucp->uc_mcontext.gregs[REG_RSI] = tmp;
     90 			break;
     91 		case 2:
     92 			ucp->uc_mcontext.gregs[REG_RDX] = tmp;
     93 			break;
     94 		case 3:
     95 			ucp->uc_mcontext.gregs[REG_RCX] = tmp;
     96 			break;
     97 		case 4:
     98 			ucp->uc_mcontext.gregs[REG_R8] = tmp;
     99 			break;
    100 		case 5:
    101 			ucp->uc_mcontext.gregs[REG_R9] = tmp;
    102 			break;
    103 		default:
    104 			*tsp++ = tmp;
    105 			break;
    106 		}
    107 	}
    108 
    109 	va_end(ap);
    110 
    111 	*sp = (long)resumecontext;		/* return address */
    112 
    113 	ucp->uc_mcontext.gregs[REG_SP] = (greg_t)sp;
    114 }
    115 
    116 
    117 static void
    118 resumecontext(void)
    119 {
    120 	ucontext_t uc;
    121 
    122 	(void) getcontext(&uc);
    123 	(void) setcontext(uc.uc_link);
    124 }
    125