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_notrace)
106	HMT_MEDIUM
107
108	mfcr	r0
109	stw	r0,8(r1)
110	HVSC				/* invoke the hypervisor */
111	lwz	r0,8(r1)
112	mtcrf	0xff,r0
113	blr				/* return r3 = status */
114
115_GLOBAL_TOC(plpar_hcall_norets)
116	HMT_MEDIUM
117
118	mfcr	r0
119	stw	r0,8(r1)
120	HCALL_BRANCH(plpar_hcall_norets_trace)
121	HVSC				/* invoke the hypervisor */
122
123	lwz	r0,8(r1)
124	mtcrf	0xff,r0
125	blr				/* return r3 = status */
126
127#ifdef CONFIG_TRACEPOINTS
128plpar_hcall_norets_trace:
129	HCALL_INST_PRECALL(R4)
130	HVSC
131	HCALL_INST_POSTCALL_NORETS
132	lwz	r0,8(r1)
133	mtcrf	0xff,r0
134	blr
135#endif
136
137_GLOBAL_TOC(plpar_hcall)
138	HMT_MEDIUM
139
140	mfcr	r0
141	stw	r0,8(r1)
142
143	HCALL_BRANCH(plpar_hcall_trace)
144
145	std     r4,STK_PARAM(R4)(r1)     /* Save ret buffer */
146
147	mr	r4,r5
148	mr	r5,r6
149	mr	r6,r7
150	mr	r7,r8
151	mr	r8,r9
152	mr	r9,r10
153
154	HVSC				/* invoke the hypervisor */
155
156	ld	r12,STK_PARAM(R4)(r1)
157	std	r4,  0(r12)
158	std	r5,  8(r12)
159	std	r6, 16(r12)
160	std	r7, 24(r12)
161
162	lwz	r0,8(r1)
163	mtcrf	0xff,r0
164
165	blr				/* return r3 = status */
166
167#ifdef CONFIG_TRACEPOINTS
168plpar_hcall_trace:
169	HCALL_INST_PRECALL(R5)
170
171	std	r4,STK_PARAM(R4)(r1)
172	mr	r0,r4
173
174	mr	r4,r5
175	mr	r5,r6
176	mr	r6,r7
177	mr	r7,r8
178	mr	r8,r9
179	mr	r9,r10
180
181	HVSC
182
183	ld	r12,STK_PARAM(R4)(r1)
184	std	r4,0(r12)
185	std	r5,8(r12)
186	std	r6,16(r12)
187	std	r7,24(r12)
188
189	HCALL_INST_POSTCALL(r12)
190
191	lwz	r0,8(r1)
192	mtcrf	0xff,r0
193
194	blr
195#endif
196
197/*
198 * plpar_hcall_raw can be called in real mode. kexec/kdump need some
199 * hypervisor calls to be executed in real mode. So plpar_hcall_raw
200 * does not access the per cpu hypervisor call statistics variables,
201 * since these variables may not be present in the RMO region.
202 */
203_GLOBAL(plpar_hcall_raw)
204	HMT_MEDIUM
205
206	mfcr	r0
207	stw	r0,8(r1)
208
209	std     r4,STK_PARAM(R4)(r1)     /* Save ret buffer */
210
211	mr	r4,r5
212	mr	r5,r6
213	mr	r6,r7
214	mr	r7,r8
215	mr	r8,r9
216	mr	r9,r10
217
218	HVSC				/* invoke the hypervisor */
219
220	ld	r12,STK_PARAM(R4)(r1)
221	std	r4,  0(r12)
222	std	r5,  8(r12)
223	std	r6, 16(r12)
224	std	r7, 24(r12)
225
226	lwz	r0,8(r1)
227	mtcrf	0xff,r0
228
229	blr				/* return r3 = status */
230
231_GLOBAL_TOC(plpar_hcall9)
232	HMT_MEDIUM
233
234	mfcr	r0
235	stw	r0,8(r1)
236
237	HCALL_BRANCH(plpar_hcall9_trace)
238
239	std     r4,STK_PARAM(R4)(r1)     /* Save ret buffer */
240
241	mr	r4,r5
242	mr	r5,r6
243	mr	r6,r7
244	mr	r7,r8
245	mr	r8,r9
246	mr	r9,r10
247	ld	r10,STK_PARAM(R11)(r1)	 /* put arg7 in R10 */
248	ld	r11,STK_PARAM(R12)(r1)	 /* put arg8 in R11 */
249	ld	r12,STK_PARAM(R13)(r1)    /* put arg9 in R12 */
250
251	HVSC				/* invoke the hypervisor */
252
253	mr	r0,r12
254	ld	r12,STK_PARAM(R4)(r1)
255	std	r4,  0(r12)
256	std	r5,  8(r12)
257	std	r6, 16(r12)
258	std	r7, 24(r12)
259	std	r8, 32(r12)
260	std	r9, 40(r12)
261	std	r10,48(r12)
262	std	r11,56(r12)
263	std	r0, 64(r12)
264
265	lwz	r0,8(r1)
266	mtcrf	0xff,r0
267
268	blr				/* return r3 = status */
269
270#ifdef CONFIG_TRACEPOINTS
271plpar_hcall9_trace:
272	HCALL_INST_PRECALL(R5)
273
274	std	r4,STK_PARAM(R4)(r1)
275	mr	r0,r4
276
277	mr	r4,r5
278	mr	r5,r6
279	mr	r6,r7
280	mr	r7,r8
281	mr	r8,r9
282	mr	r9,r10
283	ld	r10,STACK_FRAME_OVERHEAD+STK_PARAM(R11)(r1)
284	ld	r11,STACK_FRAME_OVERHEAD+STK_PARAM(R12)(r1)
285	ld	r12,STACK_FRAME_OVERHEAD+STK_PARAM(R13)(r1)
286
287	HVSC
288
289	mr	r0,r12
290	ld	r12,STACK_FRAME_OVERHEAD+STK_PARAM(R4)(r1)
291	std	r4,0(r12)
292	std	r5,8(r12)
293	std	r6,16(r12)
294	std	r7,24(r12)
295	std	r8,32(r12)
296	std	r9,40(r12)
297	std	r10,48(r12)
298	std	r11,56(r12)
299	std	r0,64(r12)
300
301	HCALL_INST_POSTCALL(r12)
302
303	lwz	r0,8(r1)
304	mtcrf	0xff,r0
305
306	blr
307#endif
308
309/* See plpar_hcall_raw to see why this is needed */
310_GLOBAL(plpar_hcall9_raw)
311	HMT_MEDIUM
312
313	mfcr	r0
314	stw	r0,8(r1)
315
316	std     r4,STK_PARAM(R4)(r1)     /* Save ret buffer */
317
318	mr	r4,r5
319	mr	r5,r6
320	mr	r6,r7
321	mr	r7,r8
322	mr	r8,r9
323	mr	r9,r10
324	ld	r10,STK_PARAM(R11)(r1)	 /* put arg7 in R10 */
325	ld	r11,STK_PARAM(R12)(r1)	 /* put arg8 in R11 */
326	ld	r12,STK_PARAM(R13)(r1)    /* put arg9 in R12 */
327
328	HVSC				/* invoke the hypervisor */
329
330	mr	r0,r12
331	ld	r12,STK_PARAM(R4)(r1)
332	std	r4,  0(r12)
333	std	r5,  8(r12)
334	std	r6, 16(r12)
335	std	r7, 24(r12)
336	std	r8, 32(r12)
337	std	r9, 40(r12)
338	std	r10,48(r12)
339	std	r11,56(r12)
340	std	r0, 64(r12)
341
342	lwz	r0,8(r1)
343	mtcrf	0xff,r0
344
345	blr				/* return r3 = status */
346