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

source code of linux/arch/powerpc/platforms/pseries/hvCall.S