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#include <mdb/mdb_kreg.h>
32
33/*
34 * Kernel function call invocation
35 */
36
37#if !defined(__lint)
38
39	.section	RODATA
40	.align		8
41
42	/*
43	 * A jump table containing the addresses for register argument copy
44	 * code.
45	 */
46copyargs:
47	.xword	cp0arg
48	.xword	cp1arg
49	.xword	cp2arg
50	.xword	cp3arg
51	.xword	cp4arg
52	.xword	cp5arg
53copyargsend:
54	.xword	cp6arg
55
56#endif	/* __lint */
57
58#if defined(__lint)
59/*ARGSUSED*/
60uintptr_t
61kaif_invoke(uintptr_t funcva, uint_t argc, const uintptr_t *argv,
62    kreg_t g6, kreg_t g7)
63{
64	return (0);
65}
66#else
67
68	ENTRY_NP(kaif_invoke)
69
70	save	%sp, -SA(MINFRAME), %sp
71
72	/*
73	 * Will registers suffice, or do we need to put excess args (>6) on the
74	 * stack?
75	 */
76	sub	%i1, 6, %i1	! %i1 is now num regs over 6 (if any)
77	brgz,pn	%i1, savestackargs
78	sllx	%i1, 3, %i1	! (argc - 6) * 8
79
80	/*
81	 * We have fewer than six arguments.  Below, starting at the cp6arg
82	 * label, we've got code that'll copy these arguments to the out
83	 * registers in descending order (%o5 is copied, then %o4, and so on).
84	 * We only want to move valid arguments, so we'll jump into this copy
85	 * code just before it copies our highest arg.  If we have four args,
86	 * for example, we'll jump to cp4arg.
87	 *
88	 * %i6 is now a negative word-scaled offset, which we can use to
89	 * retrieve the appropriate address from the jump table.  We start at
90	 * bottom of the table, and let the negative offset jump back to the
91	 * correct location.  If we have four arguments, %i1 will be -16.
92	 * Starting from copyargs+48 (the address of the last slot), we get
93	 * copyargs+32, which contains the address (cp4arg) to be used to copy
94	 * four arguments.
95	 */
96	setx	copyargsend, %l1, %l0
97	ldx	[%l0 + %i1], %l0
98	jmp	%l0
99	nop
100
101savestackargs:
102	/*
103	 * We have more than six arguments, and will thus need to allocate space
104	 * for the seventh and beyond on the stack.  %i1 is the number of bytes
105	 * needed to hold the seventh and higher arguments.
106	 */
107
108	/* Allocate swap space - %i1 rounded up to STACK_ALIGN */
109	add	%i1, STACK_ALIGN/2, %g1
110	and	%g1, -STACK_ALIGN, %g1
111	sub	%sp, %g1, %sp
112
113	add	%i2, 6*8, %l0			! %l0 is &argv[6]
114	add	%sp, STACK_BIAS+MINFRAME, %l1	! %l1 is base of stack reg save
115
116	/*
117	 * Copy arguments to the stack.  %i1 is the offset from the seventh arg
118	 * in argv and the offset from the base of the stack save area.
119	 */
120	sub	%i1, 8, %i1
1211:
122	ldx	[%l0 + %i1], %l2
123	stx	%l2, [%l1 + %i1]
124	brnz,pt	%i1, 1b
125	sub	%i1, 8, %i1
126
127	/*
128	 * Copy the register arguments.  The argc <= 6 case will be jumping to
129	 * one of these labels.
130	 */
131cp6arg:	ldx	[%i2 + 5*8], %o5
132cp5arg:	ldx	[%i2 + 4*8], %o4
133cp4arg:	ldx	[%i2 + 3*8], %o3
134cp3arg:	ldx	[%i2 + 2*8], %o2
135cp2arg:	ldx	[%i2 + 1*8], %o1
136cp1arg:	ldx	[%i2 + 0*8], %o0
137cp0arg:
138
139	mov	%g6, %l0
140	mov	%i3, %g6	! Restore PROC_REG for kernel call
141
142	mov	%g7, %l1
143	mov	%i4, %g7	! Restore THREAD_REG for kernel call
144
145	jmpl	%i0, %o7	! Make call
146	nop
147
148	mov	%l0, %g6
149	mov	%l1, %g7
150
151	ret
152	restore	%g0, %o0, %o0
153
154	SET_SIZE(kaif_invoke)
155
156#endif
157