1115518Smarcel/*
2115518Smarcel * Copyright (c) 2003 Marcel Moolenaar
3115518Smarcel * All rights reserved.
4115518Smarcel *
5115518Smarcel * Redistribution and use in source and binary forms, with or without
6115518Smarcel * modification, are permitted provided that the following conditions
7115518Smarcel * are met:
8115518Smarcel *
9115518Smarcel * 1. Redistributions of source code must retain the above copyright
10115518Smarcel *    notice, this list of conditions and the following disclaimer.
11115518Smarcel * 2. Redistributions in binary form must reproduce the above copyright
12115518Smarcel *    notice, this list of conditions and the following disclaimer in the
13115518Smarcel *    documentation and/or other materials provided with the distribution.
14115518Smarcel *
15115518Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16115518Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17115518Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18115518Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19115518Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20115518Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21115518Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22115518Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23115518Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24115518Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25115518Smarcel */
26115518Smarcel
27115518Smarcel#include <sys/cdefs.h>
28115518Smarcel__FBSDID("$FreeBSD$");
29115518Smarcel
30115518Smarcel#include <sys/types.h>
31115518Smarcel#include <sys/ucontext.h>
32115518Smarcel#include <machine/fpu.h>
33115518Smarcel#include <stdarg.h>
34115518Smarcel#include <stdio.h>
35124191Snectar#include <stdlib.h>
36124191Snectar#include <string.h>
37115518Smarcel
38115518Smarcelstruct fdesc {
39115518Smarcel	uint64_t ip;
40115518Smarcel	uint64_t gp;
41115518Smarcel};
42115518Smarcel
43115518Smarceltypedef void (*func_t)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t,
44115518Smarcel    uint64_t, uint64_t, uint64_t);
45115518Smarcel
46115518Smarcelstatic __inline uint64_t *
47115518Smarcelspill(uint64_t *bsp, uint64_t arg)
48115518Smarcel{
49115518Smarcel	*bsp++ = arg;
50115518Smarcel	if (((intptr_t)bsp & 0x1ff) == 0x1f8)
51115518Smarcel		*bsp++ = 0;
52115518Smarcel	return (bsp);
53115518Smarcel}
54115518Smarcel
55115518Smarcelstatic void
56115518Smarcelctx_wrapper(ucontext_t *ucp, func_t func, uint64_t *args)
57115518Smarcel{
58115518Smarcel
59115518Smarcel	(*func)(args[0], args[1], args[2], args[3], args[4], args[5], args[6],
60115518Smarcel	    args[7]);
61115518Smarcel	if (ucp->uc_link == NULL)
62115518Smarcel		exit(0);
63115518Smarcel	setcontext((const ucontext_t *)ucp->uc_link);
64115518Smarcel	/* should never get here */
65115518Smarcel	abort();
66115518Smarcel	/* NOTREACHED */
67115518Smarcel}
68115518Smarcel
69115518Smarcel__weak_reference(__makecontext, makecontext);
70115518Smarcel
71115518Smarcelvoid
72115518Smarcel__makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
73115518Smarcel{
74115518Smarcel	uint64_t *args, *bsp;
75115518Smarcel	va_list ap;
76115518Smarcel	int i;
77115518Smarcel
78115518Smarcel	/*
79115518Smarcel	 * Drop the ball completely if something's not right. We only
80115518Smarcel	 * support general registers as arguments and not more than 8
81115518Smarcel	 * of them. Things get hairy if we need to support FP registers
82115518Smarcel	 * (alignment issues) or more than 8 arguments (stack based).
83115518Smarcel	 */
84115518Smarcel	if (argc < 0 || argc > 8 || ucp == NULL ||
85115518Smarcel	    ucp->uc_stack.ss_sp == NULL || (ucp->uc_stack.ss_size & 15) ||
86115518Smarcel	    ((intptr_t)ucp->uc_stack.ss_sp & 15) ||
87115518Smarcel	    ucp->uc_stack.ss_size < MINSIGSTKSZ)
88115518Smarcel		abort();
89115518Smarcel
90115518Smarcel	/*
91115518Smarcel	 * Copy the arguments of function 'func' onto the (memory) stack.
92115518Smarcel	 * Always take up space for 8 arguments.
93115518Smarcel	 */
94115518Smarcel	va_start(ap, argc);
95115518Smarcel	args = (uint64_t*)(ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size) - 8;
96115518Smarcel	i = 0;
97115518Smarcel	while (i < argc)
98115518Smarcel		args[i++] = va_arg(ap, uint64_t);
99115518Smarcel	while (i < 8)
100115518Smarcel		args[i++] = 0;
101115518Smarcel	va_end(ap);
102115518Smarcel
103115518Smarcel	/*
104115518Smarcel	 * Push (spill) the arguments of the context wrapper onto the register
105115518Smarcel	 * stack. They get loaded by the RSE on a context switch.
106115518Smarcel	 */
107115518Smarcel	bsp = (uint64_t*)ucp->uc_stack.ss_sp;
108115518Smarcel	bsp = spill(bsp, (intptr_t)ucp);
109115518Smarcel	bsp = spill(bsp, (intptr_t)func);
110115518Smarcel	bsp = spill(bsp, (intptr_t)args);
111115518Smarcel
112115518Smarcel	/*
113115518Smarcel	 * Setup the MD portion of the context.
114115518Smarcel	 */
115115518Smarcel	memset(&ucp->uc_mcontext, 0, sizeof(ucp->uc_mcontext));
116115518Smarcel	ucp->uc_mcontext.mc_special.sp = (intptr_t)args - 16;
117115518Smarcel	ucp->uc_mcontext.mc_special.bspstore = (intptr_t)bsp;
118115657Smarcel	ucp->uc_mcontext.mc_special.pfs = (3 << 7) | 3;
119115518Smarcel	ucp->uc_mcontext.mc_special.rsc = 0xf;
120115518Smarcel	ucp->uc_mcontext.mc_special.rp = ((struct fdesc*)ctx_wrapper)->ip;
121115657Smarcel	ucp->uc_mcontext.mc_special.gp = ((struct fdesc*)ctx_wrapper)->gp;
122115518Smarcel	ucp->uc_mcontext.mc_special.fpsr = IA64_FPSR_DEFAULT;
123115518Smarcel}
124