1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2, as
4 * published by the Free Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9 * GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
14 *
15 * Copyright SUSE Linux Products GmbH 2010
16 *
17 * Authors: Alexander Graf <agraf@suse.de>
18 */
19
20#include <asm/ppc_asm.h>
21#include <asm/kvm_asm.h>
22#include <asm/reg.h>
23#include <asm/page.h>
24#include <asm/asm-offsets.h>
25
26/* Hypercall entry point. Will be patched with device tree instructions. */
27
28.global kvm_hypercall_start
29kvm_hypercall_start:
30	li	r3, -1
31	nop
32	nop
33	nop
34	blr
35
36#define KVM_MAGIC_PAGE		(-4096)
37
38#ifdef CONFIG_64BIT
39#define LL64(reg, offs, reg2)	ld	reg, (offs)(reg2)
40#define STL64(reg, offs, reg2)	std	reg, (offs)(reg2)
41#else
42#define LL64(reg, offs, reg2)	lwz	reg, (offs + 4)(reg2)
43#define STL64(reg, offs, reg2)	stw	reg, (offs + 4)(reg2)
44#endif
45
46#define SCRATCH_SAVE							\
47	/* Enable critical section. We are critical if			\
48	   shared->critical == r1 */					\
49	STL64(r1, KVM_MAGIC_PAGE + KVM_MAGIC_CRITICAL, 0);		\
50									\
51	/* Save state */						\
52	PPC_STL	r31, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH1)(0);		\
53	PPC_STL	r30, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH2)(0);		\
54	mfcr	r31;							\
55	stw	r31, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH3)(0);
56
57#define SCRATCH_RESTORE							\
58	/* Restore state */						\
59	PPC_LL	r31, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH1)(0);		\
60	lwz	r30, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH3)(0);		\
61	mtcr	r30;							\
62	PPC_LL	r30, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH2)(0);		\
63									\
64	/* Disable critical section. We are critical if			\
65	   shared->critical == r1 and r2 is always != r1 */		\
66	STL64(r2, KVM_MAGIC_PAGE + KVM_MAGIC_CRITICAL, 0);
67
68.global kvm_emulate_mtmsrd
69kvm_emulate_mtmsrd:
70
71	SCRATCH_SAVE
72
73	/* Put MSR & ~(MSR_EE|MSR_RI) in r31 */
74	LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
75	lis	r30, (~(MSR_EE | MSR_RI))@h
76	ori	r30, r30, (~(MSR_EE | MSR_RI))@l
77	and	r31, r31, r30
78
79	/* OR the register's (MSR_EE|MSR_RI) on MSR */
80kvm_emulate_mtmsrd_reg:
81	ori	r30, r0, 0
82	andi.	r30, r30, (MSR_EE|MSR_RI)
83	or	r31, r31, r30
84
85	/* Put MSR back into magic page */
86	STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
87
88	/* Check if we have to fetch an interrupt */
89	lwz	r31, (KVM_MAGIC_PAGE + KVM_MAGIC_INT)(0)
90	cmpwi	r31, 0
91	beq+	no_check
92
93	/* Check if we may trigger an interrupt */
94	andi.	r30, r30, MSR_EE
95	beq	no_check
96
97	SCRATCH_RESTORE
98
99	/* Nag hypervisor */
100kvm_emulate_mtmsrd_orig_ins:
101	tlbsync
102
103	b	kvm_emulate_mtmsrd_branch
104
105no_check:
106
107	SCRATCH_RESTORE
108
109	/* Go back to caller */
110kvm_emulate_mtmsrd_branch:
111	b	.
112kvm_emulate_mtmsrd_end:
113
114.global kvm_emulate_mtmsrd_branch_offs
115kvm_emulate_mtmsrd_branch_offs:
116	.long (kvm_emulate_mtmsrd_branch - kvm_emulate_mtmsrd) / 4
117
118.global kvm_emulate_mtmsrd_reg_offs
119kvm_emulate_mtmsrd_reg_offs:
120	.long (kvm_emulate_mtmsrd_reg - kvm_emulate_mtmsrd) / 4
121
122.global kvm_emulate_mtmsrd_orig_ins_offs
123kvm_emulate_mtmsrd_orig_ins_offs:
124	.long (kvm_emulate_mtmsrd_orig_ins - kvm_emulate_mtmsrd) / 4
125
126.global kvm_emulate_mtmsrd_len
127kvm_emulate_mtmsrd_len:
128	.long (kvm_emulate_mtmsrd_end - kvm_emulate_mtmsrd) / 4
129
130
131#define MSR_SAFE_BITS (MSR_EE | MSR_CE | MSR_ME | MSR_RI)
132#define MSR_CRITICAL_BITS ~MSR_SAFE_BITS
133
134.global kvm_emulate_mtmsr
135kvm_emulate_mtmsr:
136
137	SCRATCH_SAVE
138
139	/* Fetch old MSR in r31 */
140	LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
141
142	/* Find the changed bits between old and new MSR */
143kvm_emulate_mtmsr_reg1:
144	ori	r30, r0, 0
145	xor	r31, r30, r31
146
147	/* Check if we need to really do mtmsr */
148	LOAD_REG_IMMEDIATE(r30, MSR_CRITICAL_BITS)
149	and.	r31, r31, r30
150
151	/* No critical bits changed? Maybe we can stay in the guest. */
152	beq	maybe_stay_in_guest
153
154do_mtmsr:
155
156	SCRATCH_RESTORE
157
158	/* Just fire off the mtmsr if it's critical */
159kvm_emulate_mtmsr_orig_ins:
160	mtmsr	r0
161
162	b	kvm_emulate_mtmsr_branch
163
164maybe_stay_in_guest:
165
166	/* Get the target register in r30 */
167kvm_emulate_mtmsr_reg2:
168	ori	r30, r0, 0
169
170	/* Check if we have to fetch an interrupt */
171	lwz	r31, (KVM_MAGIC_PAGE + KVM_MAGIC_INT)(0)
172	cmpwi	r31, 0
173	beq+	no_mtmsr
174
175	/* Check if we may trigger an interrupt */
176	andi.	r31, r30, MSR_EE
177	beq	no_mtmsr
178
179	b	do_mtmsr
180
181no_mtmsr:
182
183	/* Put MSR into magic page because we don't call mtmsr */
184	STL64(r30, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
185
186	SCRATCH_RESTORE
187
188	/* Go back to caller */
189kvm_emulate_mtmsr_branch:
190	b	.
191kvm_emulate_mtmsr_end:
192
193.global kvm_emulate_mtmsr_branch_offs
194kvm_emulate_mtmsr_branch_offs:
195	.long (kvm_emulate_mtmsr_branch - kvm_emulate_mtmsr) / 4
196
197.global kvm_emulate_mtmsr_reg1_offs
198kvm_emulate_mtmsr_reg1_offs:
199	.long (kvm_emulate_mtmsr_reg1 - kvm_emulate_mtmsr) / 4
200
201.global kvm_emulate_mtmsr_reg2_offs
202kvm_emulate_mtmsr_reg2_offs:
203	.long (kvm_emulate_mtmsr_reg2 - kvm_emulate_mtmsr) / 4
204
205.global kvm_emulate_mtmsr_orig_ins_offs
206kvm_emulate_mtmsr_orig_ins_offs:
207	.long (kvm_emulate_mtmsr_orig_ins - kvm_emulate_mtmsr) / 4
208
209.global kvm_emulate_mtmsr_len
210kvm_emulate_mtmsr_len:
211	.long (kvm_emulate_mtmsr_end - kvm_emulate_mtmsr) / 4
212
213
214
215.global kvm_emulate_wrteei
216kvm_emulate_wrteei:
217
218	SCRATCH_SAVE
219
220	/* Fetch old MSR in r31 */
221	LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
222
223	/* Remove MSR_EE from old MSR */
224	li	r30, 0
225	ori	r30, r30, MSR_EE
226	andc	r31, r31, r30
227
228	/* OR new MSR_EE onto the old MSR */
229kvm_emulate_wrteei_ee:
230	ori	r31, r31, 0
231
232	/* Write new MSR value back */
233	STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
234
235	SCRATCH_RESTORE
236
237	/* Go back to caller */
238kvm_emulate_wrteei_branch:
239	b	.
240kvm_emulate_wrteei_end:
241
242.global kvm_emulate_wrteei_branch_offs
243kvm_emulate_wrteei_branch_offs:
244	.long (kvm_emulate_wrteei_branch - kvm_emulate_wrteei) / 4
245
246.global kvm_emulate_wrteei_ee_offs
247kvm_emulate_wrteei_ee_offs:
248	.long (kvm_emulate_wrteei_ee - kvm_emulate_wrteei) / 4
249
250.global kvm_emulate_wrteei_len
251kvm_emulate_wrteei_len:
252	.long (kvm_emulate_wrteei_end - kvm_emulate_wrteei) / 4
253
254
255.global kvm_emulate_mtsrin
256kvm_emulate_mtsrin:
257
258	SCRATCH_SAVE
259
260	LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
261	andi.	r31, r31, MSR_DR | MSR_IR
262	beq	kvm_emulate_mtsrin_reg1
263
264	SCRATCH_RESTORE
265
266kvm_emulate_mtsrin_orig_ins:
267	nop
268	b	kvm_emulate_mtsrin_branch
269
270kvm_emulate_mtsrin_reg1:
271	/* rX >> 26 */
272	rlwinm  r30,r0,6,26,29
273
274kvm_emulate_mtsrin_reg2:
275	stw	r0, (KVM_MAGIC_PAGE + KVM_MAGIC_SR)(r30)
276
277	SCRATCH_RESTORE
278
279	/* Go back to caller */
280kvm_emulate_mtsrin_branch:
281	b	.
282kvm_emulate_mtsrin_end:
283
284.global kvm_emulate_mtsrin_branch_offs
285kvm_emulate_mtsrin_branch_offs:
286	.long (kvm_emulate_mtsrin_branch - kvm_emulate_mtsrin) / 4
287
288.global kvm_emulate_mtsrin_reg1_offs
289kvm_emulate_mtsrin_reg1_offs:
290	.long (kvm_emulate_mtsrin_reg1 - kvm_emulate_mtsrin) / 4
291
292.global kvm_emulate_mtsrin_reg2_offs
293kvm_emulate_mtsrin_reg2_offs:
294	.long (kvm_emulate_mtsrin_reg2 - kvm_emulate_mtsrin) / 4
295
296.global kvm_emulate_mtsrin_orig_ins_offs
297kvm_emulate_mtsrin_orig_ins_offs:
298	.long (kvm_emulate_mtsrin_orig_ins - kvm_emulate_mtsrin) / 4
299
300.global kvm_emulate_mtsrin_len
301kvm_emulate_mtsrin_len:
302	.long (kvm_emulate_mtsrin_end - kvm_emulate_mtsrin) / 4
303