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