Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/powerpc/platforms/pseries/hvCall.S
26481 views
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
22
hcall_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) \
90
BEGIN_FTR_SECTION; \
91
b 1f; \
92
END_FTR_SECTION(0, 1); \
93
LOAD_REG_ADDR(r12, hcall_tracepoint_refcount) ; \
94
ld r12,0(r12); \
95
cmpdi r12,0; \
96
bne- LABEL; \
97
1:
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
137
plpar_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
184
plpar_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
293
plpar_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
372