hvCall.S 6.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9
/*
 * This file contains the generic code to perform a call to the
 * pSeries LPAR hypervisor.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 */
10
#include <linux/jump_label.h>
L
Linus Torvalds 已提交
11 12 13
#include <asm/hvcall.h>
#include <asm/processor.h>
#include <asm/ppc_asm.h>
14
#include <asm/asm-offsets.h>
15
#include <asm/ptrace.h>
16 17

	.section	".text"
L
Linus Torvalds 已提交
18
	
19 20
#ifdef CONFIG_TRACEPOINTS

21
#ifndef HAVE_JUMP_LABEL
22 23 24 25
	.section	".toc","aw"

	.globl hcall_tracepoint_refcount
hcall_tracepoint_refcount:
26
	.8byte	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 38 39 40 41 42 43 44
	std	r3,STK_PARAM(R3)(r1);				\
	std	r4,STK_PARAM(R4)(r1);				\
	std	r5,STK_PARAM(R5)(r1);				\
	std	r6,STK_PARAM(R6)(r1);				\
	std	r7,STK_PARAM(R7)(r1);				\
	std	r8,STK_PARAM(R8)(r1);				\
	std	r9,STK_PARAM(R9)(r1);				\
	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 50 51 52 53 54 55 56
	ld	r3,STACK_FRAME_OVERHEAD+STK_PARAM(R3)(r1);	\
	ld	r4,STACK_FRAME_OVERHEAD+STK_PARAM(R4)(r1);	\
	ld	r5,STACK_FRAME_OVERHEAD+STK_PARAM(R5)(r1);	\
	ld	r6,STACK_FRAME_OVERHEAD+STK_PARAM(R6)(r1);	\
	ld	r7,STACK_FRAME_OVERHEAD+STK_PARAM(R7)(r1);	\
	ld	r8,STACK_FRAME_OVERHEAD+STK_PARAM(R8)(r1);	\
	ld	r9,STACK_FRAME_OVERHEAD+STK_PARAM(R9)(r1);	\
	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 64
	ld	r0,STACK_FRAME_OVERHEAD+STK_PARAM(R3)(r1);	\
	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 74 75 76 77 78 79 80

#define HCALL_INST_POSTCALL_NORETS				\
	li	r5,0;						\
	__HCALL_INST_POSTCALL

#define HCALL_INST_POSTCALL(BUFREG)				\
	mr	r5,BUFREG;					\
	__HCALL_INST_POSTCALL

81
#ifdef HAVE_JUMP_LABEL
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
#define HCALL_BRANCH(LABEL)					\
	ARCH_STATIC_BRANCH(LABEL, hcall_tracepoint_key)
#else

/*
 * We branch around this in early init (eg when populating the MMU
 * hashtable) by using an unconditional cpu feature.
 */
#define HCALL_BRANCH(LABEL)					\
BEGIN_FTR_SECTION;						\
	b	1f;						\
END_FTR_SECTION(0, 1);						\
	ld	r12,hcall_tracepoint_refcount@toc(r2);		\
	std	r12,32(r1);					\
	cmpdi	r12,0;						\
	bne-	LABEL;						\
1:
#endif

101
#else
102 103 104
#define HCALL_INST_PRECALL(FIRST_ARG)
#define HCALL_INST_POSTCALL_NORETS
#define HCALL_INST_POSTCALL(BUFREG)
105
#define HCALL_BRANCH(LABEL)
106 107
#endif

108
_GLOBAL_TOC(plpar_hcall_norets)
109 110
	HMT_MEDIUM

L
Linus Torvalds 已提交
111 112
	mfcr	r0
	stw	r0,8(r1)
113
	HCALL_BRANCH(plpar_hcall_norets_trace)
L
Linus Torvalds 已提交
114 115 116 117 118 119
	HVSC				/* invoke the hypervisor */

	lwz	r0,8(r1)
	mtcrf	0xff,r0
	blr				/* return r3 = status */

120 121 122 123 124 125 126 127 128 129
#ifdef CONFIG_TRACEPOINTS
plpar_hcall_norets_trace:
	HCALL_INST_PRECALL(R4)
	HVSC
	HCALL_INST_POSTCALL_NORETS
	lwz	r0,8(r1)
	mtcrf	0xff,r0
	blr
#endif

130
_GLOBAL_TOC(plpar_hcall)
131 132
	HMT_MEDIUM

L
Linus Torvalds 已提交
133 134 135
	mfcr	r0
	stw	r0,8(r1)

136
	HCALL_BRANCH(plpar_hcall_trace)
137

138
	std     r4,STK_PARAM(R4)(r1)     /* Save ret buffer */
L
Linus Torvalds 已提交
139

140 141 142 143 144 145
	mr	r4,r5
	mr	r5,r6
	mr	r6,r7
	mr	r7,r8
	mr	r8,r9
	mr	r9,r10
L
Linus Torvalds 已提交
146 147 148

	HVSC				/* invoke the hypervisor */

149
	ld	r12,STK_PARAM(R4)(r1)
150 151 152 153
	std	r4,  0(r12)
	std	r5,  8(r12)
	std	r6, 16(r12)
	std	r7, 24(r12)
154

155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
	lwz	r0,8(r1)
	mtcrf	0xff,r0

	blr				/* return r3 = status */

#ifdef CONFIG_TRACEPOINTS
plpar_hcall_trace:
	HCALL_INST_PRECALL(R5)

	std	r4,STK_PARAM(R4)(r1)
	mr	r0,r4

	mr	r4,r5
	mr	r5,r6
	mr	r6,r7
	mr	r7,r8
	mr	r8,r9
	mr	r9,r10

	HVSC

	ld	r12,STK_PARAM(R4)(r1)
	std	r4,0(r12)
	std	r5,8(r12)
	std	r6,16(r12)
	std	r7,24(r12)

182
	HCALL_INST_POSTCALL(r12)
183

184 185 186
	lwz	r0,8(r1)
	mtcrf	0xff,r0

187 188
	blr
#endif
189

190 191 192 193 194 195 196 197 198 199 200 201
/*
 * plpar_hcall_raw can be called in real mode. kexec/kdump need some
 * hypervisor calls to be executed in real mode. So plpar_hcall_raw
 * does not access the per cpu hypervisor call statistics variables,
 * since these variables may not be present in the RMO region.
 */
_GLOBAL(plpar_hcall_raw)
	HMT_MEDIUM

	mfcr	r0
	stw	r0,8(r1)

202
	std     r4,STK_PARAM(R4)(r1)     /* Save ret buffer */
203 204 205 206 207 208 209 210 211 212

	mr	r4,r5
	mr	r5,r6
	mr	r6,r7
	mr	r7,r8
	mr	r8,r9
	mr	r9,r10

	HVSC				/* invoke the hypervisor */

213
	ld	r12,STK_PARAM(R4)(r1)
214 215 216 217 218 219 220 221 222 223
	std	r4,  0(r12)
	std	r5,  8(r12)
	std	r6, 16(r12)
	std	r7, 24(r12)

	lwz	r0,8(r1)
	mtcrf	0xff,r0

	blr				/* return r3 = status */

224
_GLOBAL_TOC(plpar_hcall9)
225 226 227 228 229
	HMT_MEDIUM

	mfcr	r0
	stw	r0,8(r1)

230
	HCALL_BRANCH(plpar_hcall9_trace)
231

232
	std     r4,STK_PARAM(R4)(r1)     /* Save ret buffer */
233 234 235 236 237 238 239

	mr	r4,r5
	mr	r5,r6
	mr	r6,r7
	mr	r7,r8
	mr	r8,r9
	mr	r9,r10
240 241 242
	ld	r10,STK_PARAM(R11)(r1)	 /* put arg7 in R10 */
	ld	r11,STK_PARAM(R12)(r1)	 /* put arg8 in R11 */
	ld	r12,STK_PARAM(R13)(r1)    /* put arg9 in R12 */
243 244 245

	HVSC				/* invoke the hypervisor */

246
	mr	r0,r12
247
	ld	r12,STK_PARAM(R4)(r1)
248 249 250 251 252 253 254 255
	std	r4,  0(r12)
	std	r5,  8(r12)
	std	r6, 16(r12)
	std	r7, 24(r12)
	std	r8, 32(r12)
	std	r9, 40(r12)
	std	r10,48(r12)
	std	r11,56(r12)
256
	std	r0, 64(r12)
257

258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
	lwz	r0,8(r1)
	mtcrf	0xff,r0

	blr				/* return r3 = status */

#ifdef CONFIG_TRACEPOINTS
plpar_hcall9_trace:
	HCALL_INST_PRECALL(R5)

	std	r4,STK_PARAM(R4)(r1)
	mr	r0,r4

	mr	r4,r5
	mr	r5,r6
	mr	r6,r7
	mr	r7,r8
	mr	r8,r9
	mr	r9,r10
276 277 278
	ld	r10,STACK_FRAME_OVERHEAD+STK_PARAM(R11)(r1)
	ld	r11,STACK_FRAME_OVERHEAD+STK_PARAM(R12)(r1)
	ld	r12,STACK_FRAME_OVERHEAD+STK_PARAM(R13)(r1)
279 280 281 282

	HVSC

	mr	r0,r12
283
	ld	r12,STACK_FRAME_OVERHEAD+STK_PARAM(R4)(r1)
284 285 286 287 288 289 290 291 292 293
	std	r4,0(r12)
	std	r5,8(r12)
	std	r6,16(r12)
	std	r7,24(r12)
	std	r8,32(r12)
	std	r9,40(r12)
	std	r10,48(r12)
	std	r11,56(r12)
	std	r0,64(r12)

294
	HCALL_INST_POSTCALL(r12)
295

296 297 298
	lwz	r0,8(r1)
	mtcrf	0xff,r0

299 300
	blr
#endif
301 302 303 304 305 306 307 308

/* See plpar_hcall_raw to see why this is needed */
_GLOBAL(plpar_hcall9_raw)
	HMT_MEDIUM

	mfcr	r0
	stw	r0,8(r1)

309
	std     r4,STK_PARAM(R4)(r1)     /* Save ret buffer */
310 311 312 313 314 315 316

	mr	r4,r5
	mr	r5,r6
	mr	r6,r7
	mr	r7,r8
	mr	r8,r9
	mr	r9,r10
317 318 319
	ld	r10,STK_PARAM(R11)(r1)	 /* put arg7 in R10 */
	ld	r11,STK_PARAM(R12)(r1)	 /* put arg8 in R11 */
	ld	r12,STK_PARAM(R13)(r1)    /* put arg9 in R12 */
320 321 322 323

	HVSC				/* invoke the hypervisor */

	mr	r0,r12
324
	ld	r12,STK_PARAM(R4)(r1)
325 326 327 328 329 330 331 332 333 334 335 336 337 338
	std	r4,  0(r12)
	std	r5,  8(r12)
	std	r6, 16(r12)
	std	r7, 24(r12)
	std	r8, 32(r12)
	std	r9, 40(r12)
	std	r10,48(r12)
	std	r11,56(r12)
	std	r0, 64(r12)

	lwz	r0,8(r1)
	mtcrf	0xff,r0

	blr				/* return r3 = status */