1/*
2 * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved.
3 *
4 * Author: Yu Liu, <yu.liu@freescale.com>
5 *
6 * Description:
7 * This file is derived from arch/powerpc/kvm/44x_emulate.c,
8 * by Hollis Blanchard <hollisb@us.ibm.com>.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License, version 2, as
12 * published by the Free Software Foundation.
13 */
14
15#include <asm/kvm_ppc.h>
16#include <asm/disassemble.h>
17#include <asm/dbell.h>
18
19#include "booke.h"
20#include "e500.h"
21
22#define XOP_DCBTLS  166
23#define XOP_MSGSND  206
24#define XOP_MSGCLR  238
25#define XOP_TLBIVAX 786
26#define XOP_TLBSX   914
27#define XOP_TLBRE   946
28#define XOP_TLBWE   978
29#define XOP_TLBILX  18
30#define XOP_EHPRIV  270
31
32#ifdef CONFIG_KVM_E500MC
33static int dbell2prio(ulong param)
34{
35	int msg = param & PPC_DBELL_TYPE_MASK;
36	int prio = -1;
37
38	switch (msg) {
39	case PPC_DBELL_TYPE(PPC_DBELL):
40		prio = BOOKE_IRQPRIO_DBELL;
41		break;
42	case PPC_DBELL_TYPE(PPC_DBELL_CRIT):
43		prio = BOOKE_IRQPRIO_DBELL_CRIT;
44		break;
45	default:
46		break;
47	}
48
49	return prio;
50}
51
52static int kvmppc_e500_emul_msgclr(struct kvm_vcpu *vcpu, int rb)
53{
54	ulong param = vcpu->arch.gpr[rb];
55	int prio = dbell2prio(param);
56
57	if (prio < 0)
58		return EMULATE_FAIL;
59
60	clear_bit(prio, &vcpu->arch.pending_exceptions);
61	return EMULATE_DONE;
62}
63
64static int kvmppc_e500_emul_msgsnd(struct kvm_vcpu *vcpu, int rb)
65{
66	ulong param = vcpu->arch.gpr[rb];
67	int prio = dbell2prio(rb);
68	int pir = param & PPC_DBELL_PIR_MASK;
69	int i;
70	struct kvm_vcpu *cvcpu;
71
72	if (prio < 0)
73		return EMULATE_FAIL;
74
75	kvm_for_each_vcpu(i, cvcpu, vcpu->kvm) {
76		int cpir = cvcpu->arch.shared->pir;
77		if ((param & PPC_DBELL_MSG_BRDCAST) || (cpir == pir)) {
78			set_bit(prio, &cvcpu->arch.pending_exceptions);
79			kvm_vcpu_kick(cvcpu);
80		}
81	}
82
83	return EMULATE_DONE;
84}
85#endif
86
87static int kvmppc_e500_emul_ehpriv(struct kvm_run *run, struct kvm_vcpu *vcpu,
88				   unsigned int inst, int *advance)
89{
90	int emulated = EMULATE_DONE;
91
92	switch (get_oc(inst)) {
93	case EHPRIV_OC_DEBUG:
94		run->exit_reason = KVM_EXIT_DEBUG;
95		run->debug.arch.address = vcpu->arch.pc;
96		run->debug.arch.status = 0;
97		kvmppc_account_exit(vcpu, DEBUG_EXITS);
98		emulated = EMULATE_EXIT_USER;
99		*advance = 0;
100		break;
101	default:
102		emulated = EMULATE_FAIL;
103	}
104	return emulated;
105}
106
107static int kvmppc_e500_emul_dcbtls(struct kvm_vcpu *vcpu)
108{
109	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
110
111	/* Always fail to lock the cache */
112	vcpu_e500->l1csr0 |= L1CSR0_CUL;
113	return EMULATE_DONE;
114}
115
116int kvmppc_core_emulate_op_e500(struct kvm_run *run, struct kvm_vcpu *vcpu,
117				unsigned int inst, int *advance)
118{
119	int emulated = EMULATE_DONE;
120	int ra = get_ra(inst);
121	int rb = get_rb(inst);
122	int rt = get_rt(inst);
123	gva_t ea;
124
125	switch (get_op(inst)) {
126	case 31:
127		switch (get_xop(inst)) {
128
129		case XOP_DCBTLS:
130			emulated = kvmppc_e500_emul_dcbtls(vcpu);
131			break;
132
133#ifdef CONFIG_KVM_E500MC
134		case XOP_MSGSND:
135			emulated = kvmppc_e500_emul_msgsnd(vcpu, rb);
136			break;
137
138		case XOP_MSGCLR:
139			emulated = kvmppc_e500_emul_msgclr(vcpu, rb);
140			break;
141#endif
142
143		case XOP_TLBRE:
144			emulated = kvmppc_e500_emul_tlbre(vcpu);
145			break;
146
147		case XOP_TLBWE:
148			emulated = kvmppc_e500_emul_tlbwe(vcpu);
149			break;
150
151		case XOP_TLBSX:
152			ea = kvmppc_get_ea_indexed(vcpu, ra, rb);
153			emulated = kvmppc_e500_emul_tlbsx(vcpu, ea);
154			break;
155
156		case XOP_TLBILX: {
157			int type = rt & 0x3;
158			ea = kvmppc_get_ea_indexed(vcpu, ra, rb);
159			emulated = kvmppc_e500_emul_tlbilx(vcpu, type, ea);
160			break;
161		}
162
163		case XOP_TLBIVAX:
164			ea = kvmppc_get_ea_indexed(vcpu, ra, rb);
165			emulated = kvmppc_e500_emul_tlbivax(vcpu, ea);
166			break;
167
168		case XOP_EHPRIV:
169			emulated = kvmppc_e500_emul_ehpriv(run, vcpu, inst,
170							   advance);
171			break;
172
173		default:
174			emulated = EMULATE_FAIL;
175		}
176
177		break;
178
179	default:
180		emulated = EMULATE_FAIL;
181	}
182
183	if (emulated == EMULATE_FAIL)
184		emulated = kvmppc_booke_emulate_op(run, vcpu, inst, advance);
185
186	return emulated;
187}
188
189int kvmppc_core_emulate_mtspr_e500(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
190{
191	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
192	int emulated = EMULATE_DONE;
193
194	switch (sprn) {
195#ifndef CONFIG_KVM_BOOKE_HV
196	case SPRN_PID:
197		kvmppc_set_pid(vcpu, spr_val);
198		break;
199	case SPRN_PID1:
200		if (spr_val != 0)
201			return EMULATE_FAIL;
202		vcpu_e500->pid[1] = spr_val;
203		break;
204	case SPRN_PID2:
205		if (spr_val != 0)
206			return EMULATE_FAIL;
207		vcpu_e500->pid[2] = spr_val;
208		break;
209	case SPRN_MAS0:
210		vcpu->arch.shared->mas0 = spr_val;
211		break;
212	case SPRN_MAS1:
213		vcpu->arch.shared->mas1 = spr_val;
214		break;
215	case SPRN_MAS2:
216		vcpu->arch.shared->mas2 = spr_val;
217		break;
218	case SPRN_MAS3:
219		vcpu->arch.shared->mas7_3 &= ~(u64)0xffffffff;
220		vcpu->arch.shared->mas7_3 |= spr_val;
221		break;
222	case SPRN_MAS4:
223		vcpu->arch.shared->mas4 = spr_val;
224		break;
225	case SPRN_MAS6:
226		vcpu->arch.shared->mas6 = spr_val;
227		break;
228	case SPRN_MAS7:
229		vcpu->arch.shared->mas7_3 &= (u64)0xffffffff;
230		vcpu->arch.shared->mas7_3 |= (u64)spr_val << 32;
231		break;
232#endif
233	case SPRN_L1CSR0:
234		vcpu_e500->l1csr0 = spr_val;
235		vcpu_e500->l1csr0 &= ~(L1CSR0_DCFI | L1CSR0_CLFC);
236		break;
237	case SPRN_L1CSR1:
238		vcpu_e500->l1csr1 = spr_val;
239		vcpu_e500->l1csr1 &= ~(L1CSR1_ICFI | L1CSR1_ICLFR);
240		break;
241	case SPRN_HID0:
242		vcpu_e500->hid0 = spr_val;
243		break;
244	case SPRN_HID1:
245		vcpu_e500->hid1 = spr_val;
246		break;
247
248	case SPRN_MMUCSR0:
249		emulated = kvmppc_e500_emul_mt_mmucsr0(vcpu_e500,
250				spr_val);
251		break;
252
253	case SPRN_PWRMGTCR0:
254		/*
255		 * Guest relies on host power management configurations
256		 * Treat the request as a general store
257		 */
258		vcpu->arch.pwrmgtcr0 = spr_val;
259		break;
260
261	/* extra exceptions */
262#ifdef CONFIG_SPE_POSSIBLE
263	case SPRN_IVOR32:
264		vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL] = spr_val;
265		break;
266	case SPRN_IVOR33:
267		vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_DATA] = spr_val;
268		break;
269	case SPRN_IVOR34:
270		vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND] = spr_val;
271		break;
272#endif
273#ifdef CONFIG_ALTIVEC
274	case SPRN_IVOR32:
275		vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_UNAVAIL] = spr_val;
276		break;
277	case SPRN_IVOR33:
278		vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_ASSIST] = spr_val;
279		break;
280#endif
281	case SPRN_IVOR35:
282		vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR] = spr_val;
283		break;
284#ifdef CONFIG_KVM_BOOKE_HV
285	case SPRN_IVOR36:
286		vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL] = spr_val;
287		break;
288	case SPRN_IVOR37:
289		vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL_CRIT] = spr_val;
290		break;
291#endif
292	default:
293		emulated = kvmppc_booke_emulate_mtspr(vcpu, sprn, spr_val);
294	}
295
296	return emulated;
297}
298
299int kvmppc_core_emulate_mfspr_e500(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val)
300{
301	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
302	int emulated = EMULATE_DONE;
303
304	switch (sprn) {
305#ifndef CONFIG_KVM_BOOKE_HV
306	case SPRN_PID:
307		*spr_val = vcpu_e500->pid[0];
308		break;
309	case SPRN_PID1:
310		*spr_val = vcpu_e500->pid[1];
311		break;
312	case SPRN_PID2:
313		*spr_val = vcpu_e500->pid[2];
314		break;
315	case SPRN_MAS0:
316		*spr_val = vcpu->arch.shared->mas0;
317		break;
318	case SPRN_MAS1:
319		*spr_val = vcpu->arch.shared->mas1;
320		break;
321	case SPRN_MAS2:
322		*spr_val = vcpu->arch.shared->mas2;
323		break;
324	case SPRN_MAS3:
325		*spr_val = (u32)vcpu->arch.shared->mas7_3;
326		break;
327	case SPRN_MAS4:
328		*spr_val = vcpu->arch.shared->mas4;
329		break;
330	case SPRN_MAS6:
331		*spr_val = vcpu->arch.shared->mas6;
332		break;
333	case SPRN_MAS7:
334		*spr_val = vcpu->arch.shared->mas7_3 >> 32;
335		break;
336#endif
337	case SPRN_DECAR:
338		*spr_val = vcpu->arch.decar;
339		break;
340	case SPRN_TLB0CFG:
341		*spr_val = vcpu->arch.tlbcfg[0];
342		break;
343	case SPRN_TLB1CFG:
344		*spr_val = vcpu->arch.tlbcfg[1];
345		break;
346	case SPRN_TLB0PS:
347		if (!has_feature(vcpu, VCPU_FTR_MMU_V2))
348			return EMULATE_FAIL;
349		*spr_val = vcpu->arch.tlbps[0];
350		break;
351	case SPRN_TLB1PS:
352		if (!has_feature(vcpu, VCPU_FTR_MMU_V2))
353			return EMULATE_FAIL;
354		*spr_val = vcpu->arch.tlbps[1];
355		break;
356	case SPRN_L1CSR0:
357		*spr_val = vcpu_e500->l1csr0;
358		break;
359	case SPRN_L1CSR1:
360		*spr_val = vcpu_e500->l1csr1;
361		break;
362	case SPRN_HID0:
363		*spr_val = vcpu_e500->hid0;
364		break;
365	case SPRN_HID1:
366		*spr_val = vcpu_e500->hid1;
367		break;
368	case SPRN_SVR:
369		*spr_val = vcpu_e500->svr;
370		break;
371
372	case SPRN_MMUCSR0:
373		*spr_val = 0;
374		break;
375
376	case SPRN_MMUCFG:
377		*spr_val = vcpu->arch.mmucfg;
378		break;
379	case SPRN_EPTCFG:
380		if (!has_feature(vcpu, VCPU_FTR_MMU_V2))
381			return EMULATE_FAIL;
382		/*
383		 * Legacy Linux guests access EPTCFG register even if the E.PT
384		 * category is disabled in the VM. Give them a chance to live.
385		 */
386		*spr_val = vcpu->arch.eptcfg;
387		break;
388
389	case SPRN_PWRMGTCR0:
390		*spr_val = vcpu->arch.pwrmgtcr0;
391		break;
392
393	/* extra exceptions */
394#ifdef CONFIG_SPE_POSSIBLE
395	case SPRN_IVOR32:
396		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL];
397		break;
398	case SPRN_IVOR33:
399		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_DATA];
400		break;
401	case SPRN_IVOR34:
402		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND];
403		break;
404#endif
405#ifdef CONFIG_ALTIVEC
406	case SPRN_IVOR32:
407		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_UNAVAIL];
408		break;
409	case SPRN_IVOR33:
410		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_ALTIVEC_ASSIST];
411		break;
412#endif
413	case SPRN_IVOR35:
414		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR];
415		break;
416#ifdef CONFIG_KVM_BOOKE_HV
417	case SPRN_IVOR36:
418		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL];
419		break;
420	case SPRN_IVOR37:
421		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL_CRIT];
422		break;
423#endif
424	default:
425		emulated = kvmppc_booke_emulate_mfspr(vcpu, sprn, spr_val);
426	}
427
428	return emulated;
429}
430
431