xref: /linux/arch/powerpc/platforms/pseries/hvCall.S (revision c537b994505099b7197e7d3125b942ecbcc51eb6)
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 <asm/hvcall.h>
11#include <asm/processor.h>
12#include <asm/ppc_asm.h>
13#include <asm/asm-offsets.h>
14
15#define STK_PARM(i)     (48 + ((i)-3)*8)
16
17#ifdef CONFIG_HCALL_STATS
18/*
19 * precall must preserve all registers.  use unused STK_PARM()
20 * areas to save snapshots and opcode.
21 */
22#define HCALL_INST_PRECALL					\
23	std	r3,STK_PARM(r3)(r1);	/* save opcode */	\
24	mftb	r0;			/* get timebase and */	\
25	std     r0,STK_PARM(r5)(r1);	/* save for later */	\
26BEGIN_FTR_SECTION;						\
27	mfspr	r0,SPRN_PURR;		/* get PURR and */	\
28	std	r0,STK_PARM(r6)(r1);	/* save for later */	\
29END_FTR_SECTION_IFSET(CPU_FTR_PURR);
30
31/*
32 * postcall is performed immediately before function return which
33 * allows liberal use of volatile registers.
34 */
35#define HCALL_INST_POSTCALL					\
36	ld	r4,STK_PARM(r3)(r1);	/* validate opcode */	\
37	cmpldi	cr7,r4,MAX_HCALL_OPCODE;			\
38	bgt-	cr7,1f;						\
39								\
40	/* get time and PURR snapshots after hcall */		\
41	mftb	r7;			/* timebase after */	\
42BEGIN_FTR_SECTION;						\
43	mfspr	r8,SPRN_PURR;		/* PURR after */	\
44	ld	r6,STK_PARM(r6)(r1);	/* PURR before */	\
45	subf	r6,r6,r8;		/* delta */		\
46END_FTR_SECTION_IFSET(CPU_FTR_PURR);				\
47	ld	r5,STK_PARM(r5)(r1);	/* timebase before */	\
48	subf	r5,r5,r7;		/* time delta */	\
49								\
50	/* calculate address of stat structure r4 = opcode */	\
51	srdi	r4,r4,2;		/* index into array */	\
52	mulli	r4,r4,HCALL_STAT_SIZE;				\
53	LOAD_REG_ADDR(r7, per_cpu__hcall_stats);		\
54	add	r4,r4,r7;					\
55	ld	r7,PACA_DATA_OFFSET(r13); /* per cpu offset */	\
56	add	r4,r4,r7;					\
57								\
58	/* update stats	*/					\
59	ld	r7,HCALL_STAT_CALLS(r4); /* count */		\
60	addi	r7,r7,1;					\
61	std	r7,HCALL_STAT_CALLS(r4);			\
62	ld      r7,HCALL_STAT_TB(r4);	/* timebase */		\
63	add	r7,r7,r5;					\
64	std	r7,HCALL_STAT_TB(r4);				\
65BEGIN_FTR_SECTION;						\
66	ld	r7,HCALL_STAT_PURR(r4);	/* PURR */		\
67	add	r7,r7,r6;					\
68	std	r7,HCALL_STAT_PURR(r4);				\
69END_FTR_SECTION_IFSET(CPU_FTR_PURR);				\
701:
71#else
72#define HCALL_INST_PRECALL
73#define HCALL_INST_POSTCALL
74#endif
75
76	.text
77
78_GLOBAL(plpar_hcall_norets)
79	HMT_MEDIUM
80
81	mfcr	r0
82	stw	r0,8(r1)
83
84	HCALL_INST_PRECALL
85
86	HVSC				/* invoke the hypervisor */
87
88	HCALL_INST_POSTCALL
89
90	lwz	r0,8(r1)
91	mtcrf	0xff,r0
92	blr				/* return r3 = status */
93
94_GLOBAL(plpar_hcall)
95	HMT_MEDIUM
96
97	mfcr	r0
98	stw	r0,8(r1)
99
100	HCALL_INST_PRECALL
101
102	std     r4,STK_PARM(r4)(r1)     /* Save ret buffer */
103
104	mr	r4,r5
105	mr	r5,r6
106	mr	r6,r7
107	mr	r7,r8
108	mr	r8,r9
109	mr	r9,r10
110
111	HVSC				/* invoke the hypervisor */
112
113	ld	r12,STK_PARM(r4)(r1)
114	std	r4,  0(r12)
115	std	r5,  8(r12)
116	std	r6, 16(r12)
117	std	r7, 24(r12)
118
119	HCALL_INST_POSTCALL
120
121	lwz	r0,8(r1)
122	mtcrf	0xff,r0
123
124	blr				/* return r3 = status */
125
126_GLOBAL(plpar_hcall9)
127	HMT_MEDIUM
128
129	mfcr	r0
130	stw	r0,8(r1)
131
132	HCALL_INST_PRECALL
133
134	std     r4,STK_PARM(r4)(r1)     /* Save ret buffer */
135
136	mr	r4,r5
137	mr	r5,r6
138	mr	r6,r7
139	mr	r7,r8
140	mr	r8,r9
141	mr	r9,r10
142	ld	r10,STK_PARM(r11)(r1)	 /* put arg7 in R10 */
143	ld	r11,STK_PARM(r12)(r1)	 /* put arg8 in R11 */
144	ld	r12,STK_PARM(r13)(r1)    /* put arg9 in R12 */
145
146	HVSC				/* invoke the hypervisor */
147
148	mr	r0,r12
149	ld	r12,STK_PARM(r4)(r1)
150	std	r4,  0(r12)
151	std	r5,  8(r12)
152	std	r6, 16(r12)
153	std	r7, 24(r12)
154	std	r8, 32(r12)
155	std	r9, 40(r12)
156	std	r10,48(r12)
157	std	r11,56(r12)
158	std	r0, 64(r12)
159
160	HCALL_INST_POSTCALL
161
162	lwz	r0,8(r1)
163	mtcrf	0xff,r0
164
165	blr				/* return r3 = status */
166