1219820Sjeff/*
2219820Sjeff * Copyright (c) 2003 Marcel Moolenaar
3219820Sjeff * All rights reserved.
4219820Sjeff *
5219820Sjeff * Redistribution and use in source and binary forms, with or without
6219820Sjeff * modification, are permitted provided that the following conditions
7219820Sjeff * are met:
8219820Sjeff *
9219820Sjeff * 1. Redistributions of source code must retain the above copyright
10219820Sjeff *    notice, this list of conditions and the following disclaimer.
11219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright
12219820Sjeff *    notice, this list of conditions and the following disclaimer in the
13219820Sjeff *    documentation and/or other materials provided with the distribution.
14219820Sjeff *
15219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16219820Sjeff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17219820Sjeff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18219820Sjeff * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19219820Sjeff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20219820Sjeff * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21219820Sjeff * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22219820Sjeff * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23219820Sjeff * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24219820Sjeff * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25219820Sjeff */
26219820Sjeff
27219820Sjeff#include <sys/cdefs.h>
28219820Sjeff__FBSDID("$FreeBSD$");
29219820Sjeff
30219820Sjeff#include <sys/types.h>
31219820Sjeff#include <sys/ucontext.h>
32219820Sjeff#include <machine/fpu.h>
33219820Sjeff#include <stdarg.h>
34219820Sjeff#include <stdio.h>
35255932Salfred#include <stdlib.h>
36255932Salfred#include <string.h>
37219820Sjeff
38255932Salfredstruct fdesc {
39219820Sjeff	uint64_t ip;
40255932Salfred	uint64_t gp;
41255932Salfred};
42219820Sjeff
43219820Sjefftypedef void (*func_t)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t,
44219820Sjeff    uint64_t, uint64_t, uint64_t);
45219820Sjeff
46219820Sjeffstatic __inline uint64_t *
47219820Sjeffspill(uint64_t *bsp, uint64_t arg)
48219820Sjeff{
49219820Sjeff	*bsp++ = arg;
50255932Salfred	if (((intptr_t)bsp & 0x1ff) == 0x1f8)
51255932Salfred		*bsp++ = 0;
52255932Salfred	return (bsp);
53255932Salfred}
54255932Salfred
55255932Salfredstatic void
56255932Salfredctx_wrapper(ucontext_t *ucp, func_t func, uint64_t *args)
57255932Salfred{
58255932Salfred
59255932Salfred	(*func)(args[0], args[1], args[2], args[3], args[4], args[5], args[6],
60255932Salfred	    args[7]);
61255932Salfred	if (ucp->uc_link == NULL)
62255932Salfred		exit(0);
63255932Salfred	setcontext((const ucontext_t *)ucp->uc_link);
64255932Salfred	/* should never get here */
65255932Salfred	abort();
66255932Salfred	/* NOTREACHED */
67255932Salfred}
68255932Salfred
69255932Salfred__weak_reference(__makecontext, makecontext);
70255932Salfred
71255932Salfredvoid
72255932Salfred__makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
73255932Salfred{
74255932Salfred	uint64_t *args, *bsp;
75255932Salfred	va_list ap;
76255932Salfred	int i;
77255932Salfred
78255932Salfred	/*
79255932Salfred	 * Drop the ball completely if something's not right. We only
80255932Salfred	 * support general registers as arguments and not more than 8
81255932Salfred	 * of them. Things get hairy if we need to support FP registers
82255932Salfred	 * (alignment issues) or more than 8 arguments (stack based).
83255932Salfred	 */
84255932Salfred	if (argc < 0 || argc > 8 || ucp == NULL ||
85255932Salfred	    ucp->uc_stack.ss_sp == NULL || (ucp->uc_stack.ss_size & 15) ||
86255932Salfred	    ((intptr_t)ucp->uc_stack.ss_sp & 15) ||
87255932Salfred	    ucp->uc_stack.ss_size < MINSIGSTKSZ)
88255932Salfred		abort();
89255932Salfred
90255932Salfred	/*
91255932Salfred	 * Copy the arguments of function 'func' onto the (memory) stack.
92255932Salfred	 * Always take up space for 8 arguments.
93255932Salfred	 */
94255932Salfred	va_start(ap, argc);
95255932Salfred	args = (uint64_t*)(ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size) - 8;
96255932Salfred	i = 0;
97255932Salfred	while (i < argc)
98255932Salfred		args[i++] = va_arg(ap, uint64_t);
99255932Salfred	while (i < 8)
100255932Salfred		args[i++] = 0;
101255932Salfred	va_end(ap);
102255932Salfred
103255932Salfred	/*
104255932Salfred	 * Push (spill) the arguments of the context wrapper onto the register
105255932Salfred	 * stack. They get loaded by the RSE on a context switch.
106219820Sjeff	 */
107219820Sjeff	bsp = (uint64_t*)ucp->uc_stack.ss_sp;
108219820Sjeff	bsp = spill(bsp, (intptr_t)ucp);
109219820Sjeff	bsp = spill(bsp, (intptr_t)func);
110219820Sjeff	bsp = spill(bsp, (intptr_t)args);
111219820Sjeff
112219820Sjeff	/*
113219820Sjeff	 * Setup the MD portion of the context.
114219820Sjeff	 */
115219820Sjeff	memset(&ucp->uc_mcontext, 0, sizeof(ucp->uc_mcontext));
116219820Sjeff	ucp->uc_mcontext.mc_special.sp = (intptr_t)args - 16;
117219820Sjeff	ucp->uc_mcontext.mc_special.bspstore = (intptr_t)bsp;
118219820Sjeff	ucp->uc_mcontext.mc_special.pfs = (3 << 7) | 3;
119219820Sjeff	ucp->uc_mcontext.mc_special.rsc = 0xf;
120219820Sjeff	ucp->uc_mcontext.mc_special.rp = ((struct fdesc*)ctx_wrapper)->ip;
121219820Sjeff	ucp->uc_mcontext.mc_special.gp = ((struct fdesc*)ctx_wrapper)->gp;
122219820Sjeff	ucp->uc_mcontext.mc_special.fpsr = IA64_FPSR_DEFAULT;
123219820Sjeff}
124219820Sjeff