hvCall.S 4.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12
/*
 * 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.
 */
#include <asm/hvcall.h>
#include <asm/processor.h>
#include <asm/ppc_asm.h>
13
#include <asm/asm-offsets.h>
L
Linus Torvalds 已提交
14 15 16
	
#define STK_PARM(i)     (48 + ((i)-3)*8)

17 18 19 20 21 22 23 24 25 26 27 28
#ifdef CONFIG_HCALL_STATS
/*
 * precall must preserve all registers.  use unused STK_PARM()
 * areas to save snapshots and opcode.
 */
#define HCALL_INST_PRECALL					\
	std	r3,STK_PARM(r3)(r1);	/* save opcode */	\
	mftb	r0;			/* get timebase and */	\
	std     r0,STK_PARM(r5)(r1);	/* save for later */	\
BEGIN_FTR_SECTION;						\
	mfspr	r0,SPRN_PURR;		/* get PURR and */	\
	std	r0,STK_PARM(r6)(r1);	/* save for later */	\
29
END_FTR_SECTION_IFSET(CPU_FTR_PURR);
30 31 32
	
/*
 * postcall is performed immediately before function return which
33 34 35
 * allows liberal use of volatile registers.  We branch around this
 * in early init (eg when populating the MMU hashtable) by using an
 * unconditional cpu feature.
36 37
 */
#define HCALL_INST_POSTCALL					\
38 39 40
BEGIN_FTR_SECTION;						\
	b	1f;						\
END_FTR_SECTION(0, 1);						\
41 42 43 44 45 46 47 48 49 50
	ld	r4,STK_PARM(r3)(r1);	/* validate opcode */	\
	cmpldi	cr7,r4,MAX_HCALL_OPCODE;			\
	bgt-	cr7,1f;						\
								\
	/* get time and PURR snapshots after hcall */		\
	mftb	r7;			/* timebase after */	\
BEGIN_FTR_SECTION;						\
	mfspr	r8,SPRN_PURR;		/* PURR after */	\
	ld	r6,STK_PARM(r6)(r1);	/* PURR before */	\
	subf	r6,r6,r8;		/* delta */		\
51
END_FTR_SECTION_IFSET(CPU_FTR_PURR);				\
52 53 54 55 56 57
	ld	r5,STK_PARM(r5)(r1);	/* timebase before */	\
	subf	r5,r5,r7;		/* time delta */	\
								\
	/* calculate address of stat structure r4 = opcode */	\
	srdi	r4,r4,2;		/* index into array */	\
	mulli	r4,r4,HCALL_STAT_SIZE;				\
R
Rusty Russell 已提交
58
	LOAD_REG_ADDR(r7, hcall_stats);				\
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
	add	r4,r4,r7;					\
	ld	r7,PACA_DATA_OFFSET(r13); /* per cpu offset */	\
	add	r4,r4,r7;					\
								\
	/* update stats	*/					\
	ld	r7,HCALL_STAT_CALLS(r4); /* count */		\
	addi	r7,r7,1;					\
	std	r7,HCALL_STAT_CALLS(r4);			\
	ld      r7,HCALL_STAT_TB(r4);	/* timebase */		\
	add	r7,r7,r5;					\
	std	r7,HCALL_STAT_TB(r4);				\
BEGIN_FTR_SECTION;						\
	ld	r7,HCALL_STAT_PURR(r4);	/* PURR */		\
	add	r7,r7,r6;					\
	std	r7,HCALL_STAT_PURR(r4);				\
74
END_FTR_SECTION_IFSET(CPU_FTR_PURR);				\
75 76 77 78 79 80
1:
#else
#define HCALL_INST_PRECALL
#define HCALL_INST_POSTCALL
#endif

L
Linus Torvalds 已提交
81 82 83
	.text

_GLOBAL(plpar_hcall_norets)
84 85
	HMT_MEDIUM

L
Linus Torvalds 已提交
86 87 88
	mfcr	r0
	stw	r0,8(r1)

89 90
	HCALL_INST_PRECALL

L
Linus Torvalds 已提交
91 92
	HVSC				/* invoke the hypervisor */

93 94
	HCALL_INST_POSTCALL

L
Linus Torvalds 已提交
95 96 97 98
	lwz	r0,8(r1)
	mtcrf	0xff,r0
	blr				/* return r3 = status */

99
_GLOBAL(plpar_hcall)
100 101
	HMT_MEDIUM

L
Linus Torvalds 已提交
102 103 104
	mfcr	r0
	stw	r0,8(r1)

105 106
	HCALL_INST_PRECALL

107
	std     r4,STK_PARM(r4)(r1)     /* Save ret buffer */
L
Linus Torvalds 已提交
108

109 110 111 112 113 114
	mr	r4,r5
	mr	r5,r6
	mr	r6,r7
	mr	r7,r8
	mr	r8,r9
	mr	r9,r10
L
Linus Torvalds 已提交
115 116 117

	HVSC				/* invoke the hypervisor */

118 119 120 121 122
	ld	r12,STK_PARM(r4)(r1)
	std	r4,  0(r12)
	std	r5,  8(r12)
	std	r6, 16(r12)
	std	r7, 24(r12)
123

124 125
	HCALL_INST_POSTCALL

126 127 128 129 130
	lwz	r0,8(r1)
	mtcrf	0xff,r0

	blr				/* return r3 = status */

131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
/*
 * 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)

	std     r4,STK_PARM(r4)(r1)     /* Save ret buffer */

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

	HVSC				/* invoke the hypervisor */

	ld	r12,STK_PARM(r4)(r1)
	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 */

165
_GLOBAL(plpar_hcall9)
166 167 168 169 170
	HMT_MEDIUM

	mfcr	r0
	stw	r0,8(r1)

171 172
	HCALL_INST_PRECALL

173 174 175 176 177 178 179 180 181 182 183
	std     r4,STK_PARM(r4)(r1)     /* Save ret buffer */

	mr	r4,r5
	mr	r5,r6
	mr	r6,r7
	mr	r7,r8
	mr	r8,r9
	mr	r9,r10
	ld	r10,STK_PARM(r11)(r1)	 /* put arg7 in R10 */
	ld	r11,STK_PARM(r12)(r1)	 /* put arg8 in R11 */
	ld	r12,STK_PARM(r13)(r1)    /* put arg9 in R12 */
184 185 186

	HVSC				/* invoke the hypervisor */

187
	mr	r0,r12
188 189 190 191 192 193 194 195 196
	ld	r12,STK_PARM(r4)(r1)
	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)
197
	std	r0, 64(r12)
198

199 200
	HCALL_INST_POSTCALL

201 202 203 204
	lwz	r0,8(r1)
	mtcrf	0xff,r0

	blr				/* return r3 = status */