1141963Swpaul/*-
2141963Swpaul * Copyright (c) 2005
3141963Swpaul *      Bill Paul <wpaul@windriver.com>.  All rights reserved.
4141963Swpaul *
5141963Swpaul * Redistribution and use in source and binary forms, with or without
6141963Swpaul * modification, are permitted provided that the following conditions
7141963Swpaul * are met:
8141963Swpaul * 1. Redistributions of source code must retain the above copyright
9141963Swpaul *    notice, this list of conditions and the following disclaimer.
10141963Swpaul * 2. Redistributions in binary form must reproduce the above copyright
11141963Swpaul *    notice, this list of conditions and the following disclaimer in the
12141963Swpaul *    documentation and/or other materials provided with the distribution.
13141963Swpaul * 3. All advertising materials mentioning features or use of this software
14141963Swpaul *    must display the following acknowledgement:
15141963Swpaul *      This product includes software developed by Bill Paul.
16141963Swpaul * 4. Neither the name of the author nor the names of any co-contributors
17141963Swpaul *    may be used to endorse or promote products derived from this software
18141963Swpaul *    without specific prior written permission.
19141963Swpaul *
20141963Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21141963Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22141963Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23141963Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24141963Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25141963Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26141963Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27141963Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28141963Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29141963Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30141963Swpaul * THE POSSIBILITY OF SUCH DAMAGE.
31141963Swpaul *
32141963Swpaul * The x86_64 callback routines were written and graciously submitted
33141963Swpaul * by Ville-Pertti Keinonen <will@exomi.com>.
34141963Swpaul *
35141963Swpaul * $FreeBSD$
36141963Swpaul */
37141963Swpaul
38141963Swpaul#include <machine/asmacros.h>
39141963Swpaul
40141963Swpaul/*
41141963Swpaul * Wrapper for handling up to 16 arguments. We can't really
42141963Swpaul * know how many arguments the caller will pass us. I'm taking an
43141963Swpaul * educated guess that we'll never get over 16. Handling too
44141963Swpaul * few arguments is bad. Handling too many is inefficient, but
45141963Swpaul * not fatal. If someone can think of a way to handle an arbitrary
46141963Swpaul * number of arguments with more elegant code, freel free to let
47141963Swpaul * me know.
48141963Swpaul *
49141963Swpaul * Standard amd64 calling conventions specify the following registers
50141963Swpaul * to be used for passing the first 6 arguments:
51141963Swpaul *
52141963Swpaul *   %rdi, %rsi, %rdx, %rcx, %r8, %r9
53141963Swpaul *
54141963Swpaul * Further arguments are passed on the stack (the 7th argument is
55141963Swpaul * located immediately after the return address).
56141963Swpaul *
57141963Swpaul * Windows x86_64 calling conventions only pass the first 4
58141963Swpaul * arguments in registers:
59141963Swpaul *
60141963Swpaul *   %rcx, %rdx, %r8, %r9
61141963Swpaul *
62141963Swpaul * Even when arguments are passed in registers, the stack must have
63141963Swpaul * space reserved for those arguments.  Thus the 5th argument (the
64141963Swpaul * first non-register argument) is placed 32 bytes after the return
65141963Swpaul * address.  Additionally, %rdi and %rsi must be preserved. (These
66141963Swpaul * two registers are not scratch registers in the standard convention.)
67141963Swpaul *
68141963Swpaul * Note that in this template, we load a contrived 64 bit address into
69141963Swpaul * %r11 to represent our jump address. This is to guarantee that the
70141963Swpaul * assembler leaves enough room to patch in an absolute 64-bit address
71141963Swpaul * later. The idea behind this code is that we want to avoid having to
72141963Swpaul * manually create all the wrapper functions at compile time with
73141963Swpaul * a bunch of macros. This is doable, but a) messy and b) requires
74141963Swpaul * us to maintain two separate tables (one for the UNIX function
75141963Swpaul * pointers and another with the wrappers). This means I'd have to
76141963Swpaul * update two different tables each time I added a function.
77141963Swpaul *
78141963Swpaul * To avoid this, we create the wrappers at runtime instead. The
79141963Swpaul * image patch tables now contain two pointers: one two the normal
80141963Swpaul * routine, and a blank one for the wrapper. To construct a wrapper,
81141963Swpaul * we allocate some memory and copy the template function into it,
82141963Swpaul * then patch the function pointer for the routine we want to wrap
83141963Swpaul * into the newly created wrapper. The subr_pe module can then
84141963Swpaul * simply patch the wrapper routine into the jump table into the
85141963Swpaul * windows image. As a bonus, the wrapper pointer not only serves
86141963Swpaul * as the wrapper entry point address, it's also a data pointer
87141963Swpaul * that we can pass to free() later when we unload the module.
88141963Swpaul */
89141963Swpaul
90141963Swpaul	.globl x86_64_wrap_call
91141963Swpaul	.globl x86_64_wrap_end
92141963Swpaul
93141963SwpaulENTRY(x86_64_wrap)
94145133Swpaul	push	%rbp		# insure that the stack
95145133Swpaul	mov	%rsp,%rbp	# is 16-byte aligned
96145133Swpaul	and	$-16,%rsp	#
97142035Swpaul	subq	$96,%rsp	# allocate space on stack
98142035Swpaul	mov     %rsi,96-8(%rsp)	# save %rsi
99142035Swpaul	mov     %rdi,96-16(%rsp)# save %rdi
100142035Swpaul	mov	%rcx,%r10	# temporarily save %rcx in scratch
101145133Swpaul	lea	56+8(%rbp),%rsi	# source == old stack top (stack+56)
102142035Swpaul	mov	%rsp,%rdi	# destination == new stack top
103142035Swpaul	mov	$10,%rcx	# count == 10 quadwords
104142035Swpaul	rep
105142035Swpaul	movsq			# copy old stack contents to new location
106142035Swpaul	mov	%r10,%rdi	# set up arg0 (%rcx -> %rdi)
107142035Swpaul	mov     %rdx,%rsi	# set up arg1 (%rdx -> %rsi)
108142035Swpaul	mov     %r8,%rdx	# set up arg2 (%r8 -> %rdx)
109142035Swpaul	mov     %r9,%rcx	# set up arg3 (%r9 -> %rcx)
110145133Swpaul	mov	40+8(%rbp),%r8	# set up arg4 (stack+40 -> %r8)
111145133Swpaul	mov	48+8(%rbp),%r9	# set up arg5 (stack+48 -> %r9)
112142035Swpaul	xor	%rax,%rax	# clear return value
113141963Swpaulx86_64_wrap_call:
114141963Swpaul	mov	$0xFF00FF00FF00FF00,%r11
115142035Swpaul	callq	*%r11		# call routine
116142035Swpaul	mov	96-16(%rsp),%rdi# restore %rdi
117142035Swpaul	mov	96-8(%rsp),%rsi	# restore %rsi
118145133Swpaul	leave			# delete space on stack
119141963Swpaul	ret
120141963Swpaulx86_64_wrap_end:
121141963Swpaul
122141963Swpaul/*
123141963Swpaul * Functions for invoking x86_64 callbacks.  In each case, the first
124141963Swpaul * argument is a pointer to the function.
125141963Swpaul */
126141963Swpaul
127141963SwpaulENTRY(x86_64_call1)
128215708Sbschmidt	subq	$40,%rsp
129141963Swpaul	mov	%rsi,%rcx
130141963Swpaul	call	*%rdi
131215708Sbschmidt	addq	$40,%rsp
132141963Swpaul	ret
133141963Swpaul
134141963SwpaulENTRY(x86_64_call2)
135215708Sbschmidt	subq	$40,%rsp
136141963Swpaul	mov	%rsi,%rcx
137141963Swpaul	/* %rdx is already correct */
138141963Swpaul	call	*%rdi
139215708Sbschmidt	addq	$40,%rsp
140141963Swpaul	ret
141141963Swpaul
142141963SwpaulENTRY(x86_64_call3)
143215708Sbschmidt	subq	$40,%rsp
144141963Swpaul	mov	%rcx,%r8
145141963Swpaul	mov	%rsi,%rcx
146141963Swpaul	call	*%rdi
147215708Sbschmidt	addq	$40,%rsp
148141963Swpaul	ret
149141963Swpaul
150141963SwpaulENTRY(x86_64_call4)
151141963Swpaul	subq	$40,%rsp
152141963Swpaul	mov	%r8,%r9
153141963Swpaul	mov	%rcx,%r8
154141963Swpaul	mov	%rsi,%rcx
155141963Swpaul	call	*%rdi
156141963Swpaul	addq	$40,%rsp
157141963Swpaul	ret
158141963Swpaul
159141963SwpaulENTRY(x86_64_call5)
160215708Sbschmidt	subq	$48,%rsp
161141963Swpaul	mov	%r9,32(%rsp)
162141963Swpaul	mov	%r8,%r9
163141963Swpaul	mov	%rcx,%r8
164141963Swpaul	mov	%rsi,%rcx
165141963Swpaul	call	*%rdi
166215708Sbschmidt	addq	$48,%rsp
167141963Swpaul	ret
168141963Swpaul
169141963SwpaulENTRY(x86_64_call6)
170141963Swpaul	subq	$56,%rsp
171141963Swpaul	mov	56+8(%rsp),%rax
172141963Swpaul	mov	%r9,32(%rsp)
173141963Swpaul	mov	%rax,40(%rsp)
174141963Swpaul	mov	%r8,%r9
175141963Swpaul	mov	%rcx,%r8
176141963Swpaul	mov	%rsi,%rcx
177141963Swpaul	call	*%rdi
178141963Swpaul	addq	$56,%rsp
179141963Swpaul	ret
180