e500_emulate.c 7.6 KB
Newer Older
1
/*
S
Scott Wood 已提交
2
 * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved.
3 4 5 6 7 8 9 10 11 12 13 14 15 16
 *
 * Author: Yu Liu, <yu.liu@freescale.com>
 *
 * Description:
 * This file is derived from arch/powerpc/kvm/44x_emulate.c,
 * by Hollis Blanchard <hollisb@us.ibm.com>.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License, version 2, as
 * published by the Free Software Foundation.
 */

#include <asm/kvm_ppc.h>
#include <asm/disassemble.h>
17
#include <asm/dbell.h>
18 19

#include "booke.h"
20
#include "e500.h"
21

22 23
#define XOP_MSGSND  206
#define XOP_MSGCLR  238
24 25 26 27
#define XOP_TLBIVAX 786
#define XOP_TLBSX   914
#define XOP_TLBRE   946
#define XOP_TLBWE   978
S
Scott Wood 已提交
28
#define XOP_TLBILX  18
29

30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
#ifdef CONFIG_KVM_E500MC
static int dbell2prio(ulong param)
{
	int msg = param & PPC_DBELL_TYPE_MASK;
	int prio = -1;

	switch (msg) {
	case PPC_DBELL_TYPE(PPC_DBELL):
		prio = BOOKE_IRQPRIO_DBELL;
		break;
	case PPC_DBELL_TYPE(PPC_DBELL_CRIT):
		prio = BOOKE_IRQPRIO_DBELL_CRIT;
		break;
	default:
		break;
	}

	return prio;
}

static int kvmppc_e500_emul_msgclr(struct kvm_vcpu *vcpu, int rb)
{
	ulong param = vcpu->arch.gpr[rb];
	int prio = dbell2prio(param);

	if (prio < 0)
		return EMULATE_FAIL;

	clear_bit(prio, &vcpu->arch.pending_exceptions);
	return EMULATE_DONE;
}

static int kvmppc_e500_emul_msgsnd(struct kvm_vcpu *vcpu, int rb)
{
	ulong param = vcpu->arch.gpr[rb];
	int prio = dbell2prio(rb);
	int pir = param & PPC_DBELL_PIR_MASK;
	int i;
	struct kvm_vcpu *cvcpu;

	if (prio < 0)
		return EMULATE_FAIL;

	kvm_for_each_vcpu(i, cvcpu, vcpu->kvm) {
		int cpir = cvcpu->arch.shared->pir;
		if ((param & PPC_DBELL_MSG_BRDCAST) || (cpir == pir)) {
			set_bit(prio, &cvcpu->arch.pending_exceptions);
			kvm_vcpu_kick(cvcpu);
		}
	}

	return EMULATE_DONE;
}
#endif

85 86 87 88
int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                           unsigned int inst, int *advance)
{
	int emulated = EMULATE_DONE;
89 90 91
	int ra = get_ra(inst);
	int rb = get_rb(inst);
	int rt = get_rt(inst);
92
	gva_t ea;
93 94 95 96 97

	switch (get_op(inst)) {
	case 31:
		switch (get_xop(inst)) {

98 99
#ifdef CONFIG_KVM_E500MC
		case XOP_MSGSND:
100
			emulated = kvmppc_e500_emul_msgsnd(vcpu, rb);
101 102 103
			break;

		case XOP_MSGCLR:
104
			emulated = kvmppc_e500_emul_msgclr(vcpu, rb);
105 106 107
			break;
#endif

108 109 110 111 112 113 114 115 116
		case XOP_TLBRE:
			emulated = kvmppc_e500_emul_tlbre(vcpu);
			break;

		case XOP_TLBWE:
			emulated = kvmppc_e500_emul_tlbwe(vcpu);
			break;

		case XOP_TLBSX:
117 118
			ea = kvmppc_get_ea_indexed(vcpu, ra, rb);
			emulated = kvmppc_e500_emul_tlbsx(vcpu, ea);
119 120
			break;

121 122 123 124
		case XOP_TLBILX: {
			int type = rt & 0x3;
			ea = kvmppc_get_ea_indexed(vcpu, ra, rb);
			emulated = kvmppc_e500_emul_tlbilx(vcpu, type, ea);
S
Scott Wood 已提交
125
			break;
126
		}
S
Scott Wood 已提交
127

128
		case XOP_TLBIVAX:
129 130
			ea = kvmppc_get_ea_indexed(vcpu, ra, rb);
			emulated = kvmppc_e500_emul_tlbivax(vcpu, ea);
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
			break;

		default:
			emulated = EMULATE_FAIL;
		}

		break;

	default:
		emulated = EMULATE_FAIL;
	}

	if (emulated == EMULATE_FAIL)
		emulated = kvmppc_booke_emulate_op(run, vcpu, inst, advance);

	return emulated;
}

149
int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
150 151 152 153 154
{
	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
	int emulated = EMULATE_DONE;

	switch (sprn) {
S
Scott Wood 已提交
155
#ifndef CONFIG_KVM_BOOKE_HV
156
	case SPRN_PID:
S
Scott Wood 已提交
157
		kvmppc_set_pid(vcpu, spr_val);
158 159
		break;
	case SPRN_PID1:
L
Liu Yu 已提交
160 161
		if (spr_val != 0)
			return EMULATE_FAIL;
162 163
		vcpu_e500->pid[1] = spr_val;
		break;
164
	case SPRN_PID2:
L
Liu Yu 已提交
165 166
		if (spr_val != 0)
			return EMULATE_FAIL;
167 168
		vcpu_e500->pid[2] = spr_val;
		break;
169
	case SPRN_MAS0:
170 171
		vcpu->arch.shared->mas0 = spr_val;
		break;
172
	case SPRN_MAS1:
173 174
		vcpu->arch.shared->mas1 = spr_val;
		break;
175
	case SPRN_MAS2:
176 177
		vcpu->arch.shared->mas2 = spr_val;
		break;
178
	case SPRN_MAS3:
179 180
		vcpu->arch.shared->mas7_3 &= ~(u64)0xffffffff;
		vcpu->arch.shared->mas7_3 |= spr_val;
S
Scott Wood 已提交
181
		break;
182
	case SPRN_MAS4:
183 184
		vcpu->arch.shared->mas4 = spr_val;
		break;
185
	case SPRN_MAS6:
186 187
		vcpu->arch.shared->mas6 = spr_val;
		break;
188
	case SPRN_MAS7:
189 190
		vcpu->arch.shared->mas7_3 &= (u64)0xffffffff;
		vcpu->arch.shared->mas7_3 |= (u64)spr_val << 32;
S
Scott Wood 已提交
191
		break;
S
Scott Wood 已提交
192
#endif
193 194 195 196
	case SPRN_L1CSR0:
		vcpu_e500->l1csr0 = spr_val;
		vcpu_e500->l1csr0 &= ~(L1CSR0_DCFI | L1CSR0_CLFC);
		break;
197
	case SPRN_L1CSR1:
198 199
		vcpu_e500->l1csr1 = spr_val;
		break;
200
	case SPRN_HID0:
201 202
		vcpu_e500->hid0 = spr_val;
		break;
203
	case SPRN_HID1:
204 205
		vcpu_e500->hid1 = spr_val;
		break;
206

207 208
	case SPRN_MMUCSR0:
		emulated = kvmppc_e500_emul_mt_mmucsr0(vcpu_e500,
209
				spr_val);
210 211
		break;

212 213
	/* extra exceptions */
	case SPRN_IVOR32:
214
		vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL] = spr_val;
215 216
		break;
	case SPRN_IVOR33:
217
		vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_DATA] = spr_val;
218 219
		break;
	case SPRN_IVOR34:
220
		vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND] = spr_val;
221 222
		break;
	case SPRN_IVOR35:
223
		vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR] = spr_val;
224
		break;
S
Scott Wood 已提交
225 226 227 228 229 230 231 232
#ifdef CONFIG_KVM_BOOKE_HV
	case SPRN_IVOR36:
		vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL] = spr_val;
		break;
	case SPRN_IVOR37:
		vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL_CRIT] = spr_val;
		break;
#endif
233
	default:
234
		emulated = kvmppc_booke_emulate_mtspr(vcpu, sprn, spr_val);
235 236 237 238 239
	}

	return emulated;
}

240
int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val)
241 242 243 244 245
{
	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
	int emulated = EMULATE_DONE;

	switch (sprn) {
S
Scott Wood 已提交
246
#ifndef CONFIG_KVM_BOOKE_HV
247
	case SPRN_PID:
248 249
		*spr_val = vcpu_e500->pid[0];
		break;
250
	case SPRN_PID1:
251 252
		*spr_val = vcpu_e500->pid[1];
		break;
253
	case SPRN_PID2:
254 255
		*spr_val = vcpu_e500->pid[2];
		break;
256
	case SPRN_MAS0:
257 258
		*spr_val = vcpu->arch.shared->mas0;
		break;
259
	case SPRN_MAS1:
260 261
		*spr_val = vcpu->arch.shared->mas1;
		break;
262
	case SPRN_MAS2:
263 264
		*spr_val = vcpu->arch.shared->mas2;
		break;
265
	case SPRN_MAS3:
266
		*spr_val = (u32)vcpu->arch.shared->mas7_3;
267
		break;
268
	case SPRN_MAS4:
269 270
		*spr_val = vcpu->arch.shared->mas4;
		break;
271
	case SPRN_MAS6:
272 273
		*spr_val = vcpu->arch.shared->mas6;
		break;
274
	case SPRN_MAS7:
275
		*spr_val = vcpu->arch.shared->mas7_3 >> 32;
276
		break;
S
Scott Wood 已提交
277
#endif
278 279 280
	case SPRN_DECAR:
		*spr_val = vcpu->arch.decar;
		break;
281
	case SPRN_TLB0CFG:
282 283
		*spr_val = vcpu->arch.tlbcfg[0];
		break;
284
	case SPRN_TLB1CFG:
285 286
		*spr_val = vcpu->arch.tlbcfg[1];
		break;
287 288 289 290 291 292 293 294 295 296
	case SPRN_TLB0PS:
		if (!has_feature(vcpu, VCPU_FTR_MMU_V2))
			return EMULATE_FAIL;
		*spr_val = vcpu->arch.tlbps[0];
		break;
	case SPRN_TLB1PS:
		if (!has_feature(vcpu, VCPU_FTR_MMU_V2))
			return EMULATE_FAIL;
		*spr_val = vcpu->arch.tlbps[1];
		break;
297
	case SPRN_L1CSR0:
298 299
		*spr_val = vcpu_e500->l1csr0;
		break;
300
	case SPRN_L1CSR1:
301 302
		*spr_val = vcpu_e500->l1csr1;
		break;
303
	case SPRN_HID0:
304 305
		*spr_val = vcpu_e500->hid0;
		break;
306
	case SPRN_HID1:
307 308
		*spr_val = vcpu_e500->hid1;
		break;
S
Scott Wood 已提交
309
	case SPRN_SVR:
310 311
		*spr_val = vcpu_e500->svr;
		break;
312

313
	case SPRN_MMUCSR0:
314 315
		*spr_val = 0;
		break;
316

317
	case SPRN_MMUCFG:
318 319
		*spr_val = vcpu->arch.mmucfg;
		break;
320 321 322 323 324 325 326 327 328
	case SPRN_EPTCFG:
		if (!has_feature(vcpu, VCPU_FTR_MMU_V2))
			return EMULATE_FAIL;
		/*
		 * Legacy Linux guests access EPTCFG register even if the E.PT
		 * category is disabled in the VM. Give them a chance to live.
		 */
		*spr_val = vcpu->arch.eptcfg;
		break;
329

330 331
	/* extra exceptions */
	case SPRN_IVOR32:
332
		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL];
333 334
		break;
	case SPRN_IVOR33:
335
		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_DATA];
336 337
		break;
	case SPRN_IVOR34:
338
		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND];
339 340
		break;
	case SPRN_IVOR35:
341
		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR];
342
		break;
S
Scott Wood 已提交
343 344
#ifdef CONFIG_KVM_BOOKE_HV
	case SPRN_IVOR36:
345
		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL];
S
Scott Wood 已提交
346 347
		break;
	case SPRN_IVOR37:
348
		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL_CRIT];
S
Scott Wood 已提交
349 350
		break;
#endif
351
	default:
352
		emulated = kvmppc_booke_emulate_mfspr(vcpu, sprn, spr_val);
353 354 355 356 357
	}

	return emulated;
}