1/*  Special support for trampolines
2 *
3 *   Copyright (C) 1996-2020 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	.cfi_startproc
60	mflr	r0		/* save return address */
61        bcl	20,31,.LCF0	/* load up __trampoline_initial into r7 */
62	.cfi_register lr,r0
63.LCF0:
64        mflr	r11
65        addi	r7,r11,trampoline_initial-4-.LCF0 /* trampoline address -4 */
66
67	cmpwi	cr1,r4,trampoline_size	/* verify that the trampoline is big enough */
68	srwi	r4,r4,2		/* # words to move */
69	addi	r9,r3,-4	/* adjust pointer for lwzu */
70	mtctr	r4
71	blt	cr1,.Labort
72
73	mtlr	r0
74
75	/* Copy the instructions to the stack */
76.Lmove:
77	lwzu	r10,4(r7)
78	stwu	r10,4(r9)
79	bdnz	.Lmove
80
81	/* Store correct function and static chain */
82	stw	r5,.Lfunc(r3)
83	stw	r6,.Lchain(r3)
84
85	/* Now flush both caches */
86	mtctr	r4
87.Lcache:
88	icbi	0,r3
89	dcbf	0,r3
90	addi	r3,r3,4
91	bdnz	.Lcache
92
93	/* Finally synchronize things & return */
94	sync
95	isync
96	blr
97
98.Labort:
99/* Use a longcall sequence in the non PIC case on VxWorks, to prevent
100   possible relocation errors if this is module-loaded very far away from
101   the 'abort' entry point.  */
102#if defined (__VXWORKS__) && ! (defined __PIC__ || defined __pic__)
103        lis   r11,JUMP_TARGET(abort)@ha
104        addic r11,r11,JUMP_TARGET(abort)@l
105        mtlr  r11
106        blrl
107#else
108
109#if (defined __PIC__ || defined __pic__) && defined HAVE_AS_REL16
110	bcl	20,31,1f
1111:	mflr	r30
112	addis	r30,r30,_GLOBAL_OFFSET_TABLE_-1b@ha
113	addi	r30,r30,_GLOBAL_OFFSET_TABLE_-1b@l
114#endif
115	bl	JUMP_TARGET(abort)
116#endif
117	.cfi_endproc
118FUNC_END(__trampoline_setup)
119
120#elif _CALL_ELF == 2
121	.type	trampoline_initial,@object
122	.align	3
123trampoline_initial:
124	ld	r11,.Lchain(r12)
125	ld	r12,.Lfunc(r12)
126	mtctr	r12
127	bctr
128.Lfunc = .-trampoline_initial
129	.quad	0			/* will be replaced with function address */
130.Lchain = .-trampoline_initial
131	.quad	0			/* will be replaced with static chain */
132
133trampoline_size = .-trampoline_initial
134	.size	trampoline_initial,trampoline_size
135
136
137/* R3 = stack address to store trampoline */
138/* R4 = length of trampoline area */
139/* R5 = function address */
140/* R6 = static chain */
141
142#ifndef __PCREL__
143	.pushsection ".toc","aw"
144.LC0:
145	.quad	trampoline_initial-8
146	.popsection
147#endif
148
149FUNC_START(__trampoline_setup)
150	.cfi_startproc
151#ifdef __PCREL__
152	pla 7,(trampoline_initial-8)@pcrel
153#else
154	addis 7,2,.LC0@toc@ha
155	ld 7,.LC0@toc@l(7)	/* trampoline address -8 */
156#endif
157
158	cmpwi	cr1,r4,trampoline_size	/* verify that the trampoline is big enough */
159	srwi	r4,r4,3		/* # doublewords to move */
160	addi	r9,r3,-8	/* adjust pointer for stdu */
161	mtctr	r4
162	blt	cr1,.Labort
163
164	/* Copy the instructions to the stack */
165.Lmove:
166	ldu	r10,8(r7)
167	stdu	r10,8(r9)
168	bdnz	.Lmove
169
170	/* Store correct function and static chain */
171	std	r5,.Lfunc(r3)
172	std	r6,.Lchain(r3)
173
174	/* Now flush both caches */
175	mtctr	r4
176.Lcache:
177	icbi	0,r3
178	dcbf	0,r3
179	addi	r3,r3,8
180	bdnz	.Lcache
181
182	/* Finally synchronize things & return */
183	sync
184	isync
185	blr
186
187.Labort:
188	bl	JUMP_TARGET(abort)
189	nop
190	.cfi_endproc
191FUNC_END(__trampoline_setup)
192
193#endif
194