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#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <sys/asm_linkage.h>
30
31/*
32 * Kernel function call invocation
33 */
34
35#if defined(__lint)
36/*ARGSUSED*/
37uintptr_t
38kaif_invoke(uintptr_t funcva, uint_t argc, const uintptr_t argv[])
39{
40	return (0);
41}
42#else
43	/*
44	 * A jump table containing the addresses for register argument copy
45	 * code.
46	 */
47copyargs:
48	.quad	cp0arg
49	.quad	cp1arg
50	.quad	cp2arg
51	.quad	cp3arg
52	.quad	cp4arg
53	.quad	cp5arg
54	.quad	cp6arg
55
56	/*
57	 * This is going to be fun.  We were called with the function pointer
58	 * in in %rsi, argc in %rdx, and a pointer to an array of uintptr_t's
59	 * (the arguments to be passed) in %rcx.  In the worst case, we need
60	 * to move the first six arguments from the array to %rdi, %rsi, %rdx,
61	 * %rcx, %r8, and %r9.  The remaining arguments need to be copied from
62	 * the array to 0(%rsp), 8(%rsp), and so on.  Then we can call the
63	 * function.
64	 */
65
66	ENTRY_NP(kaif_invoke)
67
68	pushq	%rbp
69	movq	%rsp, %rbp
70	pushq	%r12			/* our extra stack space */
71	clrq	%r12
72
73	movq	%rdi, %rax		/* function pointer */
74	movq	%rdx, %rdi		/* argv */
75
76	cmpq	$6, %rsi
77	jle	stackdone
78
79	/*
80	 * More than six arguments.  Reserve space for the seventh and beyond on
81	 * the stack, and copy them in.  To make the copy easier, we're going to
82	 * pretend to reserve space on the stack for all of the arguments, thus
83	 * allowing us to use the same scaling for the store as we do for the
84	 * load.  When we're done copying the excess arguments, we'll move %rsp
85	 * back, reclaiming the extra space we reserved.
86	 */
87	movq	%rsi, %r12
88	subq	$6, %r12
89	shlq	$3, %r12
90	subq	%r12, %rsp
91	subq	$0x30, %rsp		/* reserve 6 arg space for scaling */
92
931:	decq	%rsi
94	movq	(%rdx, %rsi, 8), %r9
95	movq	%r9, (%rsp, %rsi, 8)
96	cmpq	$6, %rsi
97	jg	1b
98
99	addq	$0x30, %rsp		/* restore scaling arg space */
100
101stackdone:
102	/*
103	 * Excess arguments have been copied and stripped from argc (or there
104	 * weren't any to begin with).  Copy the first five to their ABI-
105	 * designated registers.  We have to do this somewhat carefully, as
106	 * argc (%rdx) and argv (%rsi) are in to-be-trampled registers.
107	 */
108	leaq	copyargs(%rip), %r9
109	shlq	$3, %rsi
110	addq	%rsi, %r9
111	jmp	*(%r9)
112
113cp6arg:	movq	0x28(%rdi), %r9
114cp5arg:	movq	0x20(%rdi), %r8
115cp4arg:	movq	0x18(%rdi), %rcx
116cp3arg:	movq	0x10(%rdi), %rdx
117cp2arg:	movq	0x08(%rdi), %rsi
118cp1arg: movq	0x00(%rdi), %rdi
119cp0arg:
120
121	/* Arguments are copied.  Time to call the function */
122	call	*%rax
123
124	/*
125	 * Deallocate the stack-based arguments, if any, and return to the
126	 * caller.
127	 */
128
129	addq	%r12, %rsp
130	popq	%r12
131	leave
132	ret
133
134	SET_SIZE(kaif_invoke)
135
136#endif
137