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