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