e500_emulate.c 8.2 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
#define XOP_EHPRIV  270
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 85
#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

86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
static int kvmppc_e500_emul_ehpriv(struct kvm_run *run, struct kvm_vcpu *vcpu,
				   unsigned int inst, int *advance)
{
	int emulated = EMULATE_DONE;

	switch (get_oc(inst)) {
	case EHPRIV_OC_DEBUG:
		run->exit_reason = KVM_EXIT_DEBUG;
		run->debug.arch.address = vcpu->arch.pc;
		run->debug.arch.status = 0;
		kvmppc_account_exit(vcpu, DEBUG_EXITS);
		emulated = EMULATE_EXIT_USER;
		*advance = 0;
		break;
	default:
		emulated = EMULATE_FAIL;
	}
	return emulated;
}

106 107
int kvmppc_core_emulate_op_e500(struct kvm_run *run, struct kvm_vcpu *vcpu,
				unsigned int inst, int *advance)
108 109
{
	int emulated = EMULATE_DONE;
110 111 112
	int ra = get_ra(inst);
	int rb = get_rb(inst);
	int rt = get_rt(inst);
113
	gva_t ea;
114 115 116 117 118

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

119 120
#ifdef CONFIG_KVM_E500MC
		case XOP_MSGSND:
121
			emulated = kvmppc_e500_emul_msgsnd(vcpu, rb);
122 123 124
			break;

		case XOP_MSGCLR:
125
			emulated = kvmppc_e500_emul_msgclr(vcpu, rb);
126 127 128
			break;
#endif

129 130 131 132 133 134 135 136 137
		case XOP_TLBRE:
			emulated = kvmppc_e500_emul_tlbre(vcpu);
			break;

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

		case XOP_TLBSX:
138 139
			ea = kvmppc_get_ea_indexed(vcpu, ra, rb);
			emulated = kvmppc_e500_emul_tlbsx(vcpu, ea);
140 141
			break;

142 143 144 145
		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 已提交
146
			break;
147
		}
S
Scott Wood 已提交
148

149
		case XOP_TLBIVAX:
150 151
			ea = kvmppc_get_ea_indexed(vcpu, ra, rb);
			emulated = kvmppc_e500_emul_tlbivax(vcpu, ea);
152 153
			break;

154 155 156 157 158
		case XOP_EHPRIV:
			emulated = kvmppc_e500_emul_ehpriv(run, vcpu, inst,
							   advance);
			break;

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
		default:
			emulated = EMULATE_FAIL;
		}

		break;

	default:
		emulated = EMULATE_FAIL;
	}

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

	return emulated;
}

175
int kvmppc_core_emulate_mtspr_e500(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
176 177 178 179 180
{
	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
	int emulated = EMULATE_DONE;

	switch (sprn) {
S
Scott Wood 已提交
181
#ifndef CONFIG_KVM_BOOKE_HV
182
	case SPRN_PID:
S
Scott Wood 已提交
183
		kvmppc_set_pid(vcpu, spr_val);
184 185
		break;
	case SPRN_PID1:
L
Liu Yu 已提交
186 187
		if (spr_val != 0)
			return EMULATE_FAIL;
188 189
		vcpu_e500->pid[1] = spr_val;
		break;
190
	case SPRN_PID2:
L
Liu Yu 已提交
191 192
		if (spr_val != 0)
			return EMULATE_FAIL;
193 194
		vcpu_e500->pid[2] = spr_val;
		break;
195
	case SPRN_MAS0:
196 197
		vcpu->arch.shared->mas0 = spr_val;
		break;
198
	case SPRN_MAS1:
199 200
		vcpu->arch.shared->mas1 = spr_val;
		break;
201
	case SPRN_MAS2:
202 203
		vcpu->arch.shared->mas2 = spr_val;
		break;
204
	case SPRN_MAS3:
205 206
		vcpu->arch.shared->mas7_3 &= ~(u64)0xffffffff;
		vcpu->arch.shared->mas7_3 |= spr_val;
S
Scott Wood 已提交
207
		break;
208
	case SPRN_MAS4:
209 210
		vcpu->arch.shared->mas4 = spr_val;
		break;
211
	case SPRN_MAS6:
212 213
		vcpu->arch.shared->mas6 = spr_val;
		break;
214
	case SPRN_MAS7:
215 216
		vcpu->arch.shared->mas7_3 &= (u64)0xffffffff;
		vcpu->arch.shared->mas7_3 |= (u64)spr_val << 32;
S
Scott Wood 已提交
217
		break;
S
Scott Wood 已提交
218
#endif
219 220 221 222
	case SPRN_L1CSR0:
		vcpu_e500->l1csr0 = spr_val;
		vcpu_e500->l1csr0 &= ~(L1CSR0_DCFI | L1CSR0_CLFC);
		break;
223
	case SPRN_L1CSR1:
224 225
		vcpu_e500->l1csr1 = spr_val;
		break;
226
	case SPRN_HID0:
227 228
		vcpu_e500->hid0 = spr_val;
		break;
229
	case SPRN_HID1:
230 231
		vcpu_e500->hid1 = spr_val;
		break;
232

233 234
	case SPRN_MMUCSR0:
		emulated = kvmppc_e500_emul_mt_mmucsr0(vcpu_e500,
235
				spr_val);
236 237
		break;

238 239
	/* extra exceptions */
	case SPRN_IVOR32:
240
		vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL] = spr_val;
241 242
		break;
	case SPRN_IVOR33:
243
		vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_DATA] = spr_val;
244 245
		break;
	case SPRN_IVOR34:
246
		vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND] = spr_val;
247 248
		break;
	case SPRN_IVOR35:
249
		vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR] = spr_val;
250
		break;
S
Scott Wood 已提交
251 252 253 254 255 256 257 258
#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
259
	default:
260
		emulated = kvmppc_booke_emulate_mtspr(vcpu, sprn, spr_val);
261 262 263 264 265
	}

	return emulated;
}

266
int kvmppc_core_emulate_mfspr_e500(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val)
267 268 269 270 271
{
	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
	int emulated = EMULATE_DONE;

	switch (sprn) {
S
Scott Wood 已提交
272
#ifndef CONFIG_KVM_BOOKE_HV
273
	case SPRN_PID:
274 275
		*spr_val = vcpu_e500->pid[0];
		break;
276
	case SPRN_PID1:
277 278
		*spr_val = vcpu_e500->pid[1];
		break;
279
	case SPRN_PID2:
280 281
		*spr_val = vcpu_e500->pid[2];
		break;
282
	case SPRN_MAS0:
283 284
		*spr_val = vcpu->arch.shared->mas0;
		break;
285
	case SPRN_MAS1:
286 287
		*spr_val = vcpu->arch.shared->mas1;
		break;
288
	case SPRN_MAS2:
289 290
		*spr_val = vcpu->arch.shared->mas2;
		break;
291
	case SPRN_MAS3:
292
		*spr_val = (u32)vcpu->arch.shared->mas7_3;
293
		break;
294
	case SPRN_MAS4:
295 296
		*spr_val = vcpu->arch.shared->mas4;
		break;
297
	case SPRN_MAS6:
298 299
		*spr_val = vcpu->arch.shared->mas6;
		break;
300
	case SPRN_MAS7:
301
		*spr_val = vcpu->arch.shared->mas7_3 >> 32;
302
		break;
S
Scott Wood 已提交
303
#endif
304 305 306
	case SPRN_DECAR:
		*spr_val = vcpu->arch.decar;
		break;
307
	case SPRN_TLB0CFG:
308 309
		*spr_val = vcpu->arch.tlbcfg[0];
		break;
310
	case SPRN_TLB1CFG:
311 312
		*spr_val = vcpu->arch.tlbcfg[1];
		break;
313 314 315 316 317 318 319 320 321 322
	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;
323
	case SPRN_L1CSR0:
324 325
		*spr_val = vcpu_e500->l1csr0;
		break;
326
	case SPRN_L1CSR1:
327 328
		*spr_val = vcpu_e500->l1csr1;
		break;
329
	case SPRN_HID0:
330 331
		*spr_val = vcpu_e500->hid0;
		break;
332
	case SPRN_HID1:
333 334
		*spr_val = vcpu_e500->hid1;
		break;
S
Scott Wood 已提交
335
	case SPRN_SVR:
336 337
		*spr_val = vcpu_e500->svr;
		break;
338

339
	case SPRN_MMUCSR0:
340 341
		*spr_val = 0;
		break;
342

343
	case SPRN_MMUCFG:
344 345
		*spr_val = vcpu->arch.mmucfg;
		break;
346 347 348 349 350 351 352 353 354
	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;
355

356 357
	/* extra exceptions */
	case SPRN_IVOR32:
358
		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL];
359 360
		break;
	case SPRN_IVOR33:
361
		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_DATA];
362 363
		break;
	case SPRN_IVOR34:
364
		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND];
365 366
		break;
	case SPRN_IVOR35:
367
		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR];
368
		break;
S
Scott Wood 已提交
369 370
#ifdef CONFIG_KVM_BOOKE_HV
	case SPRN_IVOR36:
371
		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL];
S
Scott Wood 已提交
372 373
		break;
	case SPRN_IVOR37:
374
		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL_CRIT];
S
Scott Wood 已提交
375 376
		break;
#endif
377
	default:
378
		emulated = kvmppc_booke_emulate_mfspr(vcpu, sprn, spr_val);
379 380 381 382 383
	}

	return emulated;
}