e500_emulate.c 6.8 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 93 94 95 96

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

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

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

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

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

		case XOP_TLBSX:
			emulated = kvmppc_e500_emul_tlbsx(vcpu,rb);
			break;

S
Scott Wood 已提交
119 120 121 122
		case XOP_TLBILX:
			emulated = kvmppc_e500_emul_tlbilx(vcpu, rt, ra, rb);
			break;

123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
		case XOP_TLBIVAX:
			emulated = kvmppc_e500_emul_tlbivax(vcpu, ra, rb);
			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;
}

143
int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
144 145 146 147 148
{
	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
	int emulated = EMULATE_DONE;

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

201 202
	case SPRN_MMUCSR0:
		emulated = kvmppc_e500_emul_mt_mmucsr0(vcpu_e500,
203
				spr_val);
204 205
		break;

206 207
	/* extra exceptions */
	case SPRN_IVOR32:
208
		vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL] = spr_val;
209 210
		break;
	case SPRN_IVOR33:
211
		vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_DATA] = spr_val;
212 213
		break;
	case SPRN_IVOR34:
214
		vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND] = spr_val;
215 216
		break;
	case SPRN_IVOR35:
217
		vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR] = spr_val;
218
		break;
S
Scott Wood 已提交
219 220 221 222 223 224 225 226
#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
227
	default:
228
		emulated = kvmppc_booke_emulate_mtspr(vcpu, sprn, spr_val);
229 230 231 232 233
	}

	return emulated;
}

234
int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val)
235 236 237 238 239
{
	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
	int emulated = EMULATE_DONE;

	switch (sprn) {
S
Scott Wood 已提交
240
#ifndef CONFIG_KVM_BOOKE_HV
241
	case SPRN_PID:
242 243
		*spr_val = vcpu_e500->pid[0];
		break;
244
	case SPRN_PID1:
245 246
		*spr_val = vcpu_e500->pid[1];
		break;
247
	case SPRN_PID2:
248 249
		*spr_val = vcpu_e500->pid[2];
		break;
250
	case SPRN_MAS0:
251 252
		*spr_val = vcpu->arch.shared->mas0;
		break;
253
	case SPRN_MAS1:
254 255
		*spr_val = vcpu->arch.shared->mas1;
		break;
256
	case SPRN_MAS2:
257 258
		*spr_val = vcpu->arch.shared->mas2;
		break;
259
	case SPRN_MAS3:
260
		*spr_val = (u32)vcpu->arch.shared->mas7_3;
261
		break;
262
	case SPRN_MAS4:
263 264
		*spr_val = vcpu->arch.shared->mas4;
		break;
265
	case SPRN_MAS6:
266 267
		*spr_val = vcpu->arch.shared->mas6;
		break;
268
	case SPRN_MAS7:
269
		*spr_val = vcpu->arch.shared->mas7_3 >> 32;
270
		break;
S
Scott Wood 已提交
271
#endif
272
	case SPRN_TLB0CFG:
273 274
		*spr_val = vcpu->arch.tlbcfg[0];
		break;
275
	case SPRN_TLB1CFG:
276 277
		*spr_val = vcpu->arch.tlbcfg[1];
		break;
278
	case SPRN_L1CSR0:
279 280
		*spr_val = vcpu_e500->l1csr0;
		break;
281
	case SPRN_L1CSR1:
282 283
		*spr_val = vcpu_e500->l1csr1;
		break;
284
	case SPRN_HID0:
285 286
		*spr_val = vcpu_e500->hid0;
		break;
287
	case SPRN_HID1:
288 289
		*spr_val = vcpu_e500->hid1;
		break;
S
Scott Wood 已提交
290
	case SPRN_SVR:
291 292
		*spr_val = vcpu_e500->svr;
		break;
293

294
	case SPRN_MMUCSR0:
295 296
		*spr_val = 0;
		break;
297

298
	case SPRN_MMUCFG:
299 300
		*spr_val = vcpu->arch.mmucfg;
		break;
301

302 303
	/* extra exceptions */
	case SPRN_IVOR32:
304
		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL];
305 306
		break;
	case SPRN_IVOR33:
307
		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_DATA];
308 309
		break;
	case SPRN_IVOR34:
310
		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND];
311 312
		break;
	case SPRN_IVOR35:
313
		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR];
314
		break;
S
Scott Wood 已提交
315 316
#ifdef CONFIG_KVM_BOOKE_HV
	case SPRN_IVOR36:
317
		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL];
S
Scott Wood 已提交
318 319
		break;
	case SPRN_IVOR37:
320
		*spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL_CRIT];
S
Scott Wood 已提交
321 322
		break;
#endif
323
	default:
324
		emulated = kvmppc_booke_emulate_mfspr(vcpu, sprn, spr_val);
325 326 327 328 329
	}

	return emulated;
}