xref: /openbmc/linux/arch/powerpc/kernel/kvm_emul.S (revision 2209fda3)
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 * Copyright 2010-2011 Freescale Semiconductor, Inc.
17 *
18 * Authors: Alexander Graf <agraf@suse.de>
19 */
20
21#include <asm/ppc_asm.h>
22#include <asm/kvm_asm.h>
23#include <asm/reg.h>
24#include <asm/page.h>
25#include <asm/asm-offsets.h>
26#include <asm/asm-compat.h>
27
28#define KVM_MAGIC_PAGE		(-4096)
29
30#ifdef CONFIG_64BIT
31#define LL64(reg, offs, reg2)	ld	reg, (offs)(reg2)
32#define STL64(reg, offs, reg2)	std	reg, (offs)(reg2)
33#else
34#define LL64(reg, offs, reg2)	lwz	reg, (offs + 4)(reg2)
35#define STL64(reg, offs, reg2)	stw	reg, (offs + 4)(reg2)
36#endif
37
38#define SCRATCH_SAVE							\
39	/* Enable critical section. We are critical if			\
40	   shared->critical == r1 */					\
41	STL64(r1, KVM_MAGIC_PAGE + KVM_MAGIC_CRITICAL, 0);		\
42									\
43	/* Save state */						\
44	PPC_STL	r31, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH1)(0);		\
45	PPC_STL	r30, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH2)(0);		\
46	mfcr	r31;							\
47	stw	r31, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH3)(0);
48
49#define SCRATCH_RESTORE							\
50	/* Restore state */						\
51	PPC_LL	r31, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH1)(0);		\
52	lwz	r30, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH3)(0);		\
53	mtcr	r30;							\
54	PPC_LL	r30, (KVM_MAGIC_PAGE + KVM_MAGIC_SCRATCH2)(0);		\
55									\
56	/* Disable critical section. We are critical if			\
57	   shared->critical == r1 and r2 is always != r1 */		\
58	STL64(r2, KVM_MAGIC_PAGE + KVM_MAGIC_CRITICAL, 0);
59
60.global kvm_template_start
61kvm_template_start:
62
63.global kvm_emulate_mtmsrd
64kvm_emulate_mtmsrd:
65
66	SCRATCH_SAVE
67
68	/* Put MSR & ~(MSR_EE|MSR_RI) in r31 */
69	LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
70	lis	r30, (~(MSR_EE | MSR_RI))@h
71	ori	r30, r30, (~(MSR_EE | MSR_RI))@l
72	and	r31, r31, r30
73
74	/* OR the register's (MSR_EE|MSR_RI) on MSR */
75kvm_emulate_mtmsrd_reg:
76	ori	r30, r0, 0
77	andi.	r30, r30, (MSR_EE|MSR_RI)
78	or	r31, r31, r30
79
80	/* Put MSR back into magic page */
81	STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
82
83	/* Check if we have to fetch an interrupt */
84	lwz	r31, (KVM_MAGIC_PAGE + KVM_MAGIC_INT)(0)
85	cmpwi	r31, 0
86	beq+	no_check
87
88	/* Check if we may trigger an interrupt */
89	andi.	r30, r30, MSR_EE
90	beq	no_check
91
92	SCRATCH_RESTORE
93
94	/* Nag hypervisor */
95kvm_emulate_mtmsrd_orig_ins:
96	tlbsync
97
98	b	kvm_emulate_mtmsrd_branch
99
100no_check:
101
102	SCRATCH_RESTORE
103
104	/* Go back to caller */
105kvm_emulate_mtmsrd_branch:
106	b	.
107kvm_emulate_mtmsrd_end:
108
109.global kvm_emulate_mtmsrd_branch_offs
110kvm_emulate_mtmsrd_branch_offs:
111	.long (kvm_emulate_mtmsrd_branch - kvm_emulate_mtmsrd) / 4
112
113.global kvm_emulate_mtmsrd_reg_offs
114kvm_emulate_mtmsrd_reg_offs:
115	.long (kvm_emulate_mtmsrd_reg - kvm_emulate_mtmsrd) / 4
116
117.global kvm_emulate_mtmsrd_orig_ins_offs
118kvm_emulate_mtmsrd_orig_ins_offs:
119	.long (kvm_emulate_mtmsrd_orig_ins - kvm_emulate_mtmsrd) / 4
120
121.global kvm_emulate_mtmsrd_len
122kvm_emulate_mtmsrd_len:
123	.long (kvm_emulate_mtmsrd_end - kvm_emulate_mtmsrd) / 4
124
125
126#define MSR_SAFE_BITS (MSR_EE | MSR_RI)
127#define MSR_CRITICAL_BITS ~MSR_SAFE_BITS
128
129.global kvm_emulate_mtmsr
130kvm_emulate_mtmsr:
131
132	SCRATCH_SAVE
133
134	/* Fetch old MSR in r31 */
135	LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
136
137	/* Find the changed bits between old and new MSR */
138kvm_emulate_mtmsr_reg1:
139	ori	r30, r0, 0
140	xor	r31, r30, r31
141
142	/* Check if we need to really do mtmsr */
143	LOAD_REG_IMMEDIATE(r30, MSR_CRITICAL_BITS)
144	and.	r31, r31, r30
145
146	/* No critical bits changed? Maybe we can stay in the guest. */
147	beq	maybe_stay_in_guest
148
149do_mtmsr:
150
151	SCRATCH_RESTORE
152
153	/* Just fire off the mtmsr if it's critical */
154kvm_emulate_mtmsr_orig_ins:
155	mtmsr	r0
156
157	b	kvm_emulate_mtmsr_branch
158
159maybe_stay_in_guest:
160
161	/* Get the target register in r30 */
162kvm_emulate_mtmsr_reg2:
163	ori	r30, r0, 0
164
165	/* Put MSR into magic page because we don't call mtmsr */
166	STL64(r30, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
167
168	/* Check if we have to fetch an interrupt */
169	lwz	r31, (KVM_MAGIC_PAGE + KVM_MAGIC_INT)(0)
170	cmpwi	r31, 0
171	beq+	no_mtmsr
172
173	/* Check if we may trigger an interrupt */
174	andi.	r31, r30, MSR_EE
175	bne	do_mtmsr
176
177no_mtmsr:
178
179	SCRATCH_RESTORE
180
181	/* Go back to caller */
182kvm_emulate_mtmsr_branch:
183	b	.
184kvm_emulate_mtmsr_end:
185
186.global kvm_emulate_mtmsr_branch_offs
187kvm_emulate_mtmsr_branch_offs:
188	.long (kvm_emulate_mtmsr_branch - kvm_emulate_mtmsr) / 4
189
190.global kvm_emulate_mtmsr_reg1_offs
191kvm_emulate_mtmsr_reg1_offs:
192	.long (kvm_emulate_mtmsr_reg1 - kvm_emulate_mtmsr) / 4
193
194.global kvm_emulate_mtmsr_reg2_offs
195kvm_emulate_mtmsr_reg2_offs:
196	.long (kvm_emulate_mtmsr_reg2 - kvm_emulate_mtmsr) / 4
197
198.global kvm_emulate_mtmsr_orig_ins_offs
199kvm_emulate_mtmsr_orig_ins_offs:
200	.long (kvm_emulate_mtmsr_orig_ins - kvm_emulate_mtmsr) / 4
201
202.global kvm_emulate_mtmsr_len
203kvm_emulate_mtmsr_len:
204	.long (kvm_emulate_mtmsr_end - kvm_emulate_mtmsr) / 4
205
206/* also used for wrteei 1 */
207.global kvm_emulate_wrtee
208kvm_emulate_wrtee:
209
210	SCRATCH_SAVE
211
212	/* Fetch old MSR in r31 */
213	LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
214
215	/* Insert new MSR[EE] */
216kvm_emulate_wrtee_reg:
217	ori	r30, r0, 0
218	rlwimi	r31, r30, 0, MSR_EE
219
220	/*
221	 * If MSR[EE] is now set, check for a pending interrupt.
222	 * We could skip this if MSR[EE] was already on, but that
223	 * should be rare, so don't bother.
224	 */
225	andi.	r30, r30, MSR_EE
226
227	/* Put MSR into magic page because we don't call wrtee */
228	STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
229
230	beq	no_wrtee
231
232	/* Check if we have to fetch an interrupt */
233	lwz	r30, (KVM_MAGIC_PAGE + KVM_MAGIC_INT)(0)
234	cmpwi	r30, 0
235	bne	do_wrtee
236
237no_wrtee:
238	SCRATCH_RESTORE
239
240	/* Go back to caller */
241kvm_emulate_wrtee_branch:
242	b	.
243
244do_wrtee:
245	SCRATCH_RESTORE
246
247	/* Just fire off the wrtee if it's critical */
248kvm_emulate_wrtee_orig_ins:
249	wrtee	r0
250
251	b	kvm_emulate_wrtee_branch
252
253kvm_emulate_wrtee_end:
254
255.global kvm_emulate_wrtee_branch_offs
256kvm_emulate_wrtee_branch_offs:
257	.long (kvm_emulate_wrtee_branch - kvm_emulate_wrtee) / 4
258
259.global kvm_emulate_wrtee_reg_offs
260kvm_emulate_wrtee_reg_offs:
261	.long (kvm_emulate_wrtee_reg - kvm_emulate_wrtee) / 4
262
263.global kvm_emulate_wrtee_orig_ins_offs
264kvm_emulate_wrtee_orig_ins_offs:
265	.long (kvm_emulate_wrtee_orig_ins - kvm_emulate_wrtee) / 4
266
267.global kvm_emulate_wrtee_len
268kvm_emulate_wrtee_len:
269	.long (kvm_emulate_wrtee_end - kvm_emulate_wrtee) / 4
270
271.global kvm_emulate_wrteei_0
272kvm_emulate_wrteei_0:
273	SCRATCH_SAVE
274
275	/* Fetch old MSR in r31 */
276	LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
277
278	/* Remove MSR_EE from old MSR */
279	rlwinm	r31, r31, 0, ~MSR_EE
280
281	/* Write new MSR value back */
282	STL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
283
284	SCRATCH_RESTORE
285
286	/* Go back to caller */
287kvm_emulate_wrteei_0_branch:
288	b	.
289kvm_emulate_wrteei_0_end:
290
291.global kvm_emulate_wrteei_0_branch_offs
292kvm_emulate_wrteei_0_branch_offs:
293	.long (kvm_emulate_wrteei_0_branch - kvm_emulate_wrteei_0) / 4
294
295.global kvm_emulate_wrteei_0_len
296kvm_emulate_wrteei_0_len:
297	.long (kvm_emulate_wrteei_0_end - kvm_emulate_wrteei_0) / 4
298
299.global kvm_emulate_mtsrin
300kvm_emulate_mtsrin:
301
302	SCRATCH_SAVE
303
304	LL64(r31, KVM_MAGIC_PAGE + KVM_MAGIC_MSR, 0)
305	andi.	r31, r31, MSR_DR | MSR_IR
306	beq	kvm_emulate_mtsrin_reg1
307
308	SCRATCH_RESTORE
309
310kvm_emulate_mtsrin_orig_ins:
311	nop
312	b	kvm_emulate_mtsrin_branch
313
314kvm_emulate_mtsrin_reg1:
315	/* rX >> 26 */
316	rlwinm  r30,r0,6,26,29
317
318kvm_emulate_mtsrin_reg2:
319	stw	r0, (KVM_MAGIC_PAGE + KVM_MAGIC_SR)(r30)
320
321	SCRATCH_RESTORE
322
323	/* Go back to caller */
324kvm_emulate_mtsrin_branch:
325	b	.
326kvm_emulate_mtsrin_end:
327
328.global kvm_emulate_mtsrin_branch_offs
329kvm_emulate_mtsrin_branch_offs:
330	.long (kvm_emulate_mtsrin_branch - kvm_emulate_mtsrin) / 4
331
332.global kvm_emulate_mtsrin_reg1_offs
333kvm_emulate_mtsrin_reg1_offs:
334	.long (kvm_emulate_mtsrin_reg1 - kvm_emulate_mtsrin) / 4
335
336.global kvm_emulate_mtsrin_reg2_offs
337kvm_emulate_mtsrin_reg2_offs:
338	.long (kvm_emulate_mtsrin_reg2 - kvm_emulate_mtsrin) / 4
339
340.global kvm_emulate_mtsrin_orig_ins_offs
341kvm_emulate_mtsrin_orig_ins_offs:
342	.long (kvm_emulate_mtsrin_orig_ins - kvm_emulate_mtsrin) / 4
343
344.global kvm_emulate_mtsrin_len
345kvm_emulate_mtsrin_len:
346	.long (kvm_emulate_mtsrin_end - kvm_emulate_mtsrin) / 4
347
348.global kvm_template_end
349kvm_template_end:
350