xref: /OK3568_Linux_fs/kernel/arch/powerpc/platforms/pseries/hvCall.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0-or-later */
2*4882a593Smuzhiyun/*
3*4882a593Smuzhiyun * This file contains the generic code to perform a call to the
4*4882a593Smuzhiyun * pSeries LPAR hypervisor.
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun#include <linux/jump_label.h>
7*4882a593Smuzhiyun#include <asm/hvcall.h>
8*4882a593Smuzhiyun#include <asm/processor.h>
9*4882a593Smuzhiyun#include <asm/ppc_asm.h>
10*4882a593Smuzhiyun#include <asm/asm-offsets.h>
11*4882a593Smuzhiyun#include <asm/ptrace.h>
12*4882a593Smuzhiyun#include <asm/feature-fixups.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun	.section	".text"
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun#ifdef CONFIG_TRACEPOINTS
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun#ifndef CONFIG_JUMP_LABEL
19*4882a593Smuzhiyun	.section	".toc","aw"
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun	.globl hcall_tracepoint_refcount
22*4882a593Smuzhiyunhcall_tracepoint_refcount:
23*4882a593Smuzhiyun	.8byte	0
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun	.section	".text"
26*4882a593Smuzhiyun#endif
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun/*
29*4882a593Smuzhiyun * precall must preserve all registers.  use unused STK_PARAM()
30*4882a593Smuzhiyun * areas to save snapshots and opcode.
31*4882a593Smuzhiyun */
32*4882a593Smuzhiyun#define HCALL_INST_PRECALL(FIRST_REG)				\
33*4882a593Smuzhiyun	mflr	r0;						\
34*4882a593Smuzhiyun	std	r3,STK_PARAM(R3)(r1);				\
35*4882a593Smuzhiyun	std	r4,STK_PARAM(R4)(r1);				\
36*4882a593Smuzhiyun	std	r5,STK_PARAM(R5)(r1);				\
37*4882a593Smuzhiyun	std	r6,STK_PARAM(R6)(r1);				\
38*4882a593Smuzhiyun	std	r7,STK_PARAM(R7)(r1);				\
39*4882a593Smuzhiyun	std	r8,STK_PARAM(R8)(r1);				\
40*4882a593Smuzhiyun	std	r9,STK_PARAM(R9)(r1);				\
41*4882a593Smuzhiyun	std	r10,STK_PARAM(R10)(r1);				\
42*4882a593Smuzhiyun	std	r0,16(r1);					\
43*4882a593Smuzhiyun	addi	r4,r1,STK_PARAM(FIRST_REG);			\
44*4882a593Smuzhiyun	stdu	r1,-STACK_FRAME_OVERHEAD(r1);			\
45*4882a593Smuzhiyun	bl	__trace_hcall_entry;				\
46*4882a593Smuzhiyun	ld	r3,STACK_FRAME_OVERHEAD+STK_PARAM(R3)(r1);	\
47*4882a593Smuzhiyun	ld	r4,STACK_FRAME_OVERHEAD+STK_PARAM(R4)(r1);	\
48*4882a593Smuzhiyun	ld	r5,STACK_FRAME_OVERHEAD+STK_PARAM(R5)(r1);	\
49*4882a593Smuzhiyun	ld	r6,STACK_FRAME_OVERHEAD+STK_PARAM(R6)(r1);	\
50*4882a593Smuzhiyun	ld	r7,STACK_FRAME_OVERHEAD+STK_PARAM(R7)(r1);	\
51*4882a593Smuzhiyun	ld	r8,STACK_FRAME_OVERHEAD+STK_PARAM(R8)(r1);	\
52*4882a593Smuzhiyun	ld	r9,STACK_FRAME_OVERHEAD+STK_PARAM(R9)(r1);	\
53*4882a593Smuzhiyun	ld	r10,STACK_FRAME_OVERHEAD+STK_PARAM(R10)(r1)
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun/*
56*4882a593Smuzhiyun * postcall is performed immediately before function return which
57*4882a593Smuzhiyun * allows liberal use of volatile registers.
58*4882a593Smuzhiyun */
59*4882a593Smuzhiyun#define __HCALL_INST_POSTCALL					\
60*4882a593Smuzhiyun	ld	r0,STACK_FRAME_OVERHEAD+STK_PARAM(R3)(r1);	\
61*4882a593Smuzhiyun	std	r3,STACK_FRAME_OVERHEAD+STK_PARAM(R3)(r1);	\
62*4882a593Smuzhiyun	mr	r4,r3;						\
63*4882a593Smuzhiyun	mr	r3,r0;						\
64*4882a593Smuzhiyun	bl	__trace_hcall_exit;				\
65*4882a593Smuzhiyun	ld	r0,STACK_FRAME_OVERHEAD+16(r1);			\
66*4882a593Smuzhiyun	addi	r1,r1,STACK_FRAME_OVERHEAD;			\
67*4882a593Smuzhiyun	ld	r3,STK_PARAM(R3)(r1);				\
68*4882a593Smuzhiyun	mtlr	r0
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun#define HCALL_INST_POSTCALL_NORETS				\
71*4882a593Smuzhiyun	li	r5,0;						\
72*4882a593Smuzhiyun	__HCALL_INST_POSTCALL
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun#define HCALL_INST_POSTCALL(BUFREG)				\
75*4882a593Smuzhiyun	mr	r5,BUFREG;					\
76*4882a593Smuzhiyun	__HCALL_INST_POSTCALL
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun#ifdef CONFIG_JUMP_LABEL
79*4882a593Smuzhiyun#define HCALL_BRANCH(LABEL)					\
80*4882a593Smuzhiyun	ARCH_STATIC_BRANCH(LABEL, hcall_tracepoint_key)
81*4882a593Smuzhiyun#else
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun/*
84*4882a593Smuzhiyun * We branch around this in early init (eg when populating the MMU
85*4882a593Smuzhiyun * hashtable) by using an unconditional cpu feature.
86*4882a593Smuzhiyun */
87*4882a593Smuzhiyun#define HCALL_BRANCH(LABEL)					\
88*4882a593SmuzhiyunBEGIN_FTR_SECTION;						\
89*4882a593Smuzhiyun	b	1f;						\
90*4882a593SmuzhiyunEND_FTR_SECTION(0, 1);						\
91*4882a593Smuzhiyun	ld	r12,hcall_tracepoint_refcount@toc(r2);		\
92*4882a593Smuzhiyun	std	r12,32(r1);					\
93*4882a593Smuzhiyun	cmpdi	r12,0;						\
94*4882a593Smuzhiyun	bne-	LABEL;						\
95*4882a593Smuzhiyun1:
96*4882a593Smuzhiyun#endif
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun#else
99*4882a593Smuzhiyun#define HCALL_INST_PRECALL(FIRST_ARG)
100*4882a593Smuzhiyun#define HCALL_INST_POSTCALL_NORETS
101*4882a593Smuzhiyun#define HCALL_INST_POSTCALL(BUFREG)
102*4882a593Smuzhiyun#define HCALL_BRANCH(LABEL)
103*4882a593Smuzhiyun#endif
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun_GLOBAL_TOC(plpar_hcall_norets_notrace)
106*4882a593Smuzhiyun	HMT_MEDIUM
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun	mfcr	r0
109*4882a593Smuzhiyun	stw	r0,8(r1)
110*4882a593Smuzhiyun	HVSC				/* invoke the hypervisor */
111*4882a593Smuzhiyun	lwz	r0,8(r1)
112*4882a593Smuzhiyun	mtcrf	0xff,r0
113*4882a593Smuzhiyun	blr				/* return r3 = status */
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun_GLOBAL_TOC(plpar_hcall_norets)
116*4882a593Smuzhiyun	HMT_MEDIUM
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun	mfcr	r0
119*4882a593Smuzhiyun	stw	r0,8(r1)
120*4882a593Smuzhiyun	HCALL_BRANCH(plpar_hcall_norets_trace)
121*4882a593Smuzhiyun	HVSC				/* invoke the hypervisor */
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun	lwz	r0,8(r1)
124*4882a593Smuzhiyun	mtcrf	0xff,r0
125*4882a593Smuzhiyun	blr				/* return r3 = status */
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun#ifdef CONFIG_TRACEPOINTS
128*4882a593Smuzhiyunplpar_hcall_norets_trace:
129*4882a593Smuzhiyun	HCALL_INST_PRECALL(R4)
130*4882a593Smuzhiyun	HVSC
131*4882a593Smuzhiyun	HCALL_INST_POSTCALL_NORETS
132*4882a593Smuzhiyun	lwz	r0,8(r1)
133*4882a593Smuzhiyun	mtcrf	0xff,r0
134*4882a593Smuzhiyun	blr
135*4882a593Smuzhiyun#endif
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun_GLOBAL_TOC(plpar_hcall)
138*4882a593Smuzhiyun	HMT_MEDIUM
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun	mfcr	r0
141*4882a593Smuzhiyun	stw	r0,8(r1)
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun	HCALL_BRANCH(plpar_hcall_trace)
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun	std     r4,STK_PARAM(R4)(r1)     /* Save ret buffer */
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun	mr	r4,r5
148*4882a593Smuzhiyun	mr	r5,r6
149*4882a593Smuzhiyun	mr	r6,r7
150*4882a593Smuzhiyun	mr	r7,r8
151*4882a593Smuzhiyun	mr	r8,r9
152*4882a593Smuzhiyun	mr	r9,r10
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun	HVSC				/* invoke the hypervisor */
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun	ld	r12,STK_PARAM(R4)(r1)
157*4882a593Smuzhiyun	std	r4,  0(r12)
158*4882a593Smuzhiyun	std	r5,  8(r12)
159*4882a593Smuzhiyun	std	r6, 16(r12)
160*4882a593Smuzhiyun	std	r7, 24(r12)
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun	lwz	r0,8(r1)
163*4882a593Smuzhiyun	mtcrf	0xff,r0
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun	blr				/* return r3 = status */
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun#ifdef CONFIG_TRACEPOINTS
168*4882a593Smuzhiyunplpar_hcall_trace:
169*4882a593Smuzhiyun	HCALL_INST_PRECALL(R5)
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun	std	r4,STK_PARAM(R4)(r1)
172*4882a593Smuzhiyun	mr	r0,r4
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun	mr	r4,r5
175*4882a593Smuzhiyun	mr	r5,r6
176*4882a593Smuzhiyun	mr	r6,r7
177*4882a593Smuzhiyun	mr	r7,r8
178*4882a593Smuzhiyun	mr	r8,r9
179*4882a593Smuzhiyun	mr	r9,r10
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun	HVSC
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun	ld	r12,STK_PARAM(R4)(r1)
184*4882a593Smuzhiyun	std	r4,0(r12)
185*4882a593Smuzhiyun	std	r5,8(r12)
186*4882a593Smuzhiyun	std	r6,16(r12)
187*4882a593Smuzhiyun	std	r7,24(r12)
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun	HCALL_INST_POSTCALL(r12)
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun	lwz	r0,8(r1)
192*4882a593Smuzhiyun	mtcrf	0xff,r0
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun	blr
195*4882a593Smuzhiyun#endif
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun/*
198*4882a593Smuzhiyun * plpar_hcall_raw can be called in real mode. kexec/kdump need some
199*4882a593Smuzhiyun * hypervisor calls to be executed in real mode. So plpar_hcall_raw
200*4882a593Smuzhiyun * does not access the per cpu hypervisor call statistics variables,
201*4882a593Smuzhiyun * since these variables may not be present in the RMO region.
202*4882a593Smuzhiyun */
203*4882a593Smuzhiyun_GLOBAL(plpar_hcall_raw)
204*4882a593Smuzhiyun	HMT_MEDIUM
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun	mfcr	r0
207*4882a593Smuzhiyun	stw	r0,8(r1)
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun	std     r4,STK_PARAM(R4)(r1)     /* Save ret buffer */
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun	mr	r4,r5
212*4882a593Smuzhiyun	mr	r5,r6
213*4882a593Smuzhiyun	mr	r6,r7
214*4882a593Smuzhiyun	mr	r7,r8
215*4882a593Smuzhiyun	mr	r8,r9
216*4882a593Smuzhiyun	mr	r9,r10
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun	HVSC				/* invoke the hypervisor */
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun	ld	r12,STK_PARAM(R4)(r1)
221*4882a593Smuzhiyun	std	r4,  0(r12)
222*4882a593Smuzhiyun	std	r5,  8(r12)
223*4882a593Smuzhiyun	std	r6, 16(r12)
224*4882a593Smuzhiyun	std	r7, 24(r12)
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun	lwz	r0,8(r1)
227*4882a593Smuzhiyun	mtcrf	0xff,r0
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun	blr				/* return r3 = status */
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun_GLOBAL_TOC(plpar_hcall9)
232*4882a593Smuzhiyun	HMT_MEDIUM
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun	mfcr	r0
235*4882a593Smuzhiyun	stw	r0,8(r1)
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun	HCALL_BRANCH(plpar_hcall9_trace)
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun	std     r4,STK_PARAM(R4)(r1)     /* Save ret buffer */
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun	mr	r4,r5
242*4882a593Smuzhiyun	mr	r5,r6
243*4882a593Smuzhiyun	mr	r6,r7
244*4882a593Smuzhiyun	mr	r7,r8
245*4882a593Smuzhiyun	mr	r8,r9
246*4882a593Smuzhiyun	mr	r9,r10
247*4882a593Smuzhiyun	ld	r10,STK_PARAM(R11)(r1)	 /* put arg7 in R10 */
248*4882a593Smuzhiyun	ld	r11,STK_PARAM(R12)(r1)	 /* put arg8 in R11 */
249*4882a593Smuzhiyun	ld	r12,STK_PARAM(R13)(r1)    /* put arg9 in R12 */
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun	HVSC				/* invoke the hypervisor */
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun	mr	r0,r12
254*4882a593Smuzhiyun	ld	r12,STK_PARAM(R4)(r1)
255*4882a593Smuzhiyun	std	r4,  0(r12)
256*4882a593Smuzhiyun	std	r5,  8(r12)
257*4882a593Smuzhiyun	std	r6, 16(r12)
258*4882a593Smuzhiyun	std	r7, 24(r12)
259*4882a593Smuzhiyun	std	r8, 32(r12)
260*4882a593Smuzhiyun	std	r9, 40(r12)
261*4882a593Smuzhiyun	std	r10,48(r12)
262*4882a593Smuzhiyun	std	r11,56(r12)
263*4882a593Smuzhiyun	std	r0, 64(r12)
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun	lwz	r0,8(r1)
266*4882a593Smuzhiyun	mtcrf	0xff,r0
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun	blr				/* return r3 = status */
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun#ifdef CONFIG_TRACEPOINTS
271*4882a593Smuzhiyunplpar_hcall9_trace:
272*4882a593Smuzhiyun	HCALL_INST_PRECALL(R5)
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun	std	r4,STK_PARAM(R4)(r1)
275*4882a593Smuzhiyun	mr	r0,r4
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun	mr	r4,r5
278*4882a593Smuzhiyun	mr	r5,r6
279*4882a593Smuzhiyun	mr	r6,r7
280*4882a593Smuzhiyun	mr	r7,r8
281*4882a593Smuzhiyun	mr	r8,r9
282*4882a593Smuzhiyun	mr	r9,r10
283*4882a593Smuzhiyun	ld	r10,STACK_FRAME_OVERHEAD+STK_PARAM(R11)(r1)
284*4882a593Smuzhiyun	ld	r11,STACK_FRAME_OVERHEAD+STK_PARAM(R12)(r1)
285*4882a593Smuzhiyun	ld	r12,STACK_FRAME_OVERHEAD+STK_PARAM(R13)(r1)
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun	HVSC
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun	mr	r0,r12
290*4882a593Smuzhiyun	ld	r12,STACK_FRAME_OVERHEAD+STK_PARAM(R4)(r1)
291*4882a593Smuzhiyun	std	r4,0(r12)
292*4882a593Smuzhiyun	std	r5,8(r12)
293*4882a593Smuzhiyun	std	r6,16(r12)
294*4882a593Smuzhiyun	std	r7,24(r12)
295*4882a593Smuzhiyun	std	r8,32(r12)
296*4882a593Smuzhiyun	std	r9,40(r12)
297*4882a593Smuzhiyun	std	r10,48(r12)
298*4882a593Smuzhiyun	std	r11,56(r12)
299*4882a593Smuzhiyun	std	r0,64(r12)
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun	HCALL_INST_POSTCALL(r12)
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun	lwz	r0,8(r1)
304*4882a593Smuzhiyun	mtcrf	0xff,r0
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun	blr
307*4882a593Smuzhiyun#endif
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun/* See plpar_hcall_raw to see why this is needed */
310*4882a593Smuzhiyun_GLOBAL(plpar_hcall9_raw)
311*4882a593Smuzhiyun	HMT_MEDIUM
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun	mfcr	r0
314*4882a593Smuzhiyun	stw	r0,8(r1)
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun	std     r4,STK_PARAM(R4)(r1)     /* Save ret buffer */
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun	mr	r4,r5
319*4882a593Smuzhiyun	mr	r5,r6
320*4882a593Smuzhiyun	mr	r6,r7
321*4882a593Smuzhiyun	mr	r7,r8
322*4882a593Smuzhiyun	mr	r8,r9
323*4882a593Smuzhiyun	mr	r9,r10
324*4882a593Smuzhiyun	ld	r10,STK_PARAM(R11)(r1)	 /* put arg7 in R10 */
325*4882a593Smuzhiyun	ld	r11,STK_PARAM(R12)(r1)	 /* put arg8 in R11 */
326*4882a593Smuzhiyun	ld	r12,STK_PARAM(R13)(r1)    /* put arg9 in R12 */
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun	HVSC				/* invoke the hypervisor */
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun	mr	r0,r12
331*4882a593Smuzhiyun	ld	r12,STK_PARAM(R4)(r1)
332*4882a593Smuzhiyun	std	r4,  0(r12)
333*4882a593Smuzhiyun	std	r5,  8(r12)
334*4882a593Smuzhiyun	std	r6, 16(r12)
335*4882a593Smuzhiyun	std	r7, 24(r12)
336*4882a593Smuzhiyun	std	r8, 32(r12)
337*4882a593Smuzhiyun	std	r9, 40(r12)
338*4882a593Smuzhiyun	std	r10,48(r12)
339*4882a593Smuzhiyun	std	r11,56(r12)
340*4882a593Smuzhiyun	std	r0, 64(r12)
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun	lwz	r0,8(r1)
343*4882a593Smuzhiyun	mtcrf	0xff,r0
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun	blr				/* return r3 = status */
346