1/*  Special support for trampolines
2 *
3 *   Copyright (C) 1996-2018 Free Software Foundation, Inc.
4 *   Written By Michael Meissner
5 *
6 * This file is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 3, or (at your option) any
9 * later version.
10 *
11 * This file is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * General Public License for more details.
15 *
16 * Under Section 7 of GPL version 3, you are granted additional
17 * permissions described in the GCC Runtime Library Exception, version
18 * 3.1, as published by the Free Software Foundation.
19 *
20 * You should have received a copy of the GNU General Public License and
21 * a copy of the GCC Runtime Library Exception along with this program;
22 * see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23 * <http://www.gnu.org/licenses/>.
24 */
25
26/* Set up trampolines.  */
27
28	.section ".text"
29#include "ppc-asm.h"
30#include "config.h"
31
32#ifndef __powerpc64__
33	.type	trampoline_initial,@object
34	.align	2
35trampoline_initial:
36	mflr	r0
37	bcl	20,31,1f
38.Lfunc = .-trampoline_initial
39	.long	0			/* will be replaced with function address */
40.Lchain = .-trampoline_initial
41	.long	0			/* will be replaced with static chain */
421:	mflr	r11
43	mtlr	r0
44	lwz	r0,0(r11)		/* function address */
45	lwz	r11,4(r11)		/* static chain */
46	mtctr	r0
47	bctr
48
49trampoline_size = .-trampoline_initial
50	.size	trampoline_initial,trampoline_size
51
52
53/* R3 = stack address to store trampoline */
54/* R4 = length of trampoline area */
55/* R5 = function address */
56/* R6 = static chain */
57
58FUNC_START(__trampoline_setup)
59	mflr	r0		/* save return address */
60        bcl	20,31,.LCF0	/* load up __trampoline_initial into r7 */
61.LCF0:
62        mflr	r11
63        addi	r7,r11,trampoline_initial-4-.LCF0 /* trampoline address -4 */
64
65	li	r8,trampoline_size	/* verify that the trampoline is big enough */
66	cmpw	cr1,r8,r4
67	srwi	r4,r4,2		/* # words to move */
68	addi	r9,r3,-4	/* adjust pointer for lwzu */
69	mtctr	r4
70	blt	cr1,.Labort
71
72	mtlr	r0
73
74	/* Copy the instructions to the stack */
75.Lmove:
76	lwzu	r10,4(r7)
77	stwu	r10,4(r9)
78	bdnz	.Lmove
79
80	/* Store correct function and static chain */
81	stw	r5,.Lfunc(r3)
82	stw	r6,.Lchain(r3)
83
84	/* Now flush both caches */
85	mtctr	r4
86.Lcache:
87	icbi	0,r3
88	dcbf	0,r3
89	addi	r3,r3,4
90	bdnz	.Lcache
91
92	/* Finally synchronize things & return */
93	sync
94	isync
95	blr
96
97.Labort:
98/* Use a longcall sequence in the non PIC case on VxWorks, to prevent
99   possible relocation errors if this is module-loaded very far away from
100   the 'abort' entry point.  */
101#if defined (__VXWORKS__) && ! (defined __PIC__ || defined __pic__)
102        lis   r11,JUMP_TARGET(abort)@ha
103        addic r11,r11,JUMP_TARGET(abort)@l
104        mtlr  r11
105        blrl
106#else
107
108#if (defined __PIC__ || defined __pic__) && defined HAVE_AS_REL16
109	bcl	20,31,1f
1101:	mflr	r30
111	addis	r30,r30,_GLOBAL_OFFSET_TABLE_-1b@ha
112	addi	r30,r30,_GLOBAL_OFFSET_TABLE_-1b@l
113#endif
114	bl	JUMP_TARGET(abort)
115FUNC_END(__trampoline_setup)
116
117#endif
118
119#elif _CALL_ELF == 2
120	.type	trampoline_initial,@object
121	.align	3
122trampoline_initial:
123	ld	r11,.Lchain(r12)
124	ld	r12,.Lfunc(r12)
125	mtctr	r12
126	bctr
127.Lfunc = .-trampoline_initial
128	.quad	0			/* will be replaced with function address */
129.Lchain = .-trampoline_initial
130	.quad	0			/* will be replaced with static chain */
131
132trampoline_size = .-trampoline_initial
133	.size	trampoline_initial,trampoline_size
134
135
136/* R3 = stack address to store trampoline */
137/* R4 = length of trampoline area */
138/* R5 = function address */
139/* R6 = static chain */
140
141	.pushsection ".toc","aw"
142.LC0:
143	.quad	trampoline_initial-8
144	.popsection
145
146FUNC_START(__trampoline_setup)
147	addis 7,2,.LC0@toc@ha
148	ld 7,.LC0@toc@l(7)	/* trampoline address -8 */
149
150	li	r8,trampoline_size	/* verify that the trampoline is big enough */
151	cmpw	cr1,r8,r4
152	srwi	r4,r4,3		/* # doublewords to move */
153	addi	r9,r3,-8	/* adjust pointer for stdu */
154	mtctr	r4
155	blt	cr1,.Labort
156
157	/* Copy the instructions to the stack */
158.Lmove:
159	ldu	r10,8(r7)
160	stdu	r10,8(r9)
161	bdnz	.Lmove
162
163	/* Store correct function and static chain */
164	std	r5,.Lfunc(r3)
165	std	r6,.Lchain(r3)
166
167	/* Now flush both caches */
168	mtctr	r4
169.Lcache:
170	icbi	0,r3
171	dcbf	0,r3
172	addi	r3,r3,8
173	bdnz	.Lcache
174
175	/* Finally synchronize things & return */
176	sync
177	isync
178	blr
179
180.Labort:
181	bl	JUMP_TARGET(abort)
182	nop
183FUNC_END(__trampoline_setup)
184
185#endif
186