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, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include <sys/asm_linkage.h>
28
29/*
30 * Kernel function call invocation
31 */
32
33#if defined(__lint)
34/*ARGSUSED*/
35uintptr_t
36kaif_invoke(uintptr_t funcva, uint_t argc, const uintptr_t argv[])
37{
38	return (0);
39}
40#else
41	/*
42	 * A jump table containing the addresses for register argument copy
43	 * code.
44	 */
45copyargs:
46	.quad	cp0arg
47	.quad	cp1arg
48	.quad	cp2arg
49	.quad	cp3arg
50	.quad	cp4arg
51	.quad	cp5arg
52	.quad	cp6arg
53
54	/*
55	 * This is going to be fun.  We were called with the function pointer
56	 * in in %rsi, argc in %rdx, and a pointer to an array of uintptr_t's
57	 * (the arguments to be passed) in %rcx.  In the worst case, we need
58	 * to move the first six arguments from the array to %rdi, %rsi, %rdx,
59	 * %rcx, %r8, and %r9.  The remaining arguments need to be copied from
60	 * the array to 0(%rsp), 8(%rsp), and so on.  Then we can call the
61	 * function.
62	 */
63
64	ENTRY_NP(kaif_invoke)
65
66	pushq	%rbp
67	movq	%rsp, %rbp
68	pushq	%r12			/* our extra stack space */
69	clrq	%r12
70
71	movq	%rdi, %rax		/* function pointer */
72	movq	%rdx, %rdi		/* argv */
73
74	cmpq	$6, %rsi
75	jle	stackdone
76
77	/*
78	 * More than six arguments.  Reserve space for the seventh and beyond on
79	 * the stack, and copy them in.  To make the copy easier, we're going to
80	 * pretend to reserve space on the stack for all of the arguments, thus
81	 * allowing us to use the same scaling for the store as we do for the
82	 * load.  When we're done copying the excess arguments, we'll move %rsp
83	 * back, reclaiming the extra space we reserved.
84	 */
85	movq	%rsi, %r12
86	subq	$6, %r12
87	shlq	$3, %r12
88	subq	%r12, %rsp
89	subq	$0x30, %rsp		/* reserve 6 arg space for scaling */
90
911:	decq	%rsi
92	movq	(%rdx, %rsi, 8), %r9
93	movq	%r9, (%rsp, %rsi, 8)
94	cmpq	$6, %rsi
95	jg	1b
96
97	addq	$0x30, %rsp		/* restore scaling arg space */
98
99stackdone:
100	/*
101	 * Excess arguments have been copied and stripped from argc (or there
102	 * weren't any to begin with).  Copy the first five to their ABI-
103	 * designated registers.  We have to do this somewhat carefully, as
104	 * argc (%rdx) and argv (%rsi) are in to-be-trampled registers.
105	 */
106	leaq	copyargs(%rip), %r9
107	shlq	$3, %rsi
108	addq	%rsi, %r9
109	jmp	*(%r9)
110
111cp6arg:	movq	0x28(%rdi), %r9
112cp5arg:	movq	0x20(%rdi), %r8
113cp4arg:	movq	0x18(%rdi), %rcx
114cp3arg:	movq	0x10(%rdi), %rdx
115cp2arg:	movq	0x08(%rdi), %rsi
116cp1arg: movq	0x00(%rdi), %rdi
117cp0arg:
118
119	/* Arguments are copied.  Time to call the function */
120	call	*%rax
121
122	/*
123	 * Deallocate the stack-based arguments, if any, and return to the
124	 * caller.
125	 */
126
127	addq	%r12, %rsp
128	popq	%r12
129	leave
130	ret
131
132	SET_SIZE(kaif_invoke)
133
134#endif
135