Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7cdd7a95 authored by Mihai Caraman's avatar Mihai Caraman Committed by Alexander Graf
Browse files

KVM: PPC: e500: Add emulation helper for getting instruction ea



Add emulation helper for getting instruction ea and refactor tlb instruction
emulation to use it.

Signed-off-by: default avatarMihai Caraman <mihai.caraman@freescale.com>
[agraf: keep rt variable around]
Signed-off-by: default avatarAlexander Graf <agraf@suse.de>
parent e51f8f32
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -295,4 +295,15 @@ static inline void kvmppc_lazy_ee_enable(void)
#endif
}

static inline ulong kvmppc_get_ea_indexed(struct kvm_vcpu *vcpu, int ra, int rb)
{
	ulong ea;

	ea = kvmppc_get_gpr(vcpu, rb);
	if (ra)
		ea += kvmppc_get_gpr(vcpu, ra);

	return ea;
}

#endif /* __POWERPC_KVM_PPC_H__ */
+3 −3
Original line number Diff line number Diff line
@@ -129,9 +129,9 @@ int kvmppc_e500_emul_mt_mmucsr0(struct kvmppc_vcpu_e500 *vcpu_e500,
				ulong value);
int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu);
int kvmppc_e500_emul_tlbre(struct kvm_vcpu *vcpu);
int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, int ra, int rb);
int kvmppc_e500_emul_tlbilx(struct kvm_vcpu *vcpu, int rt, int ra, int rb);
int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, int rb);
int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, gva_t ea);
int kvmppc_e500_emul_tlbilx(struct kvm_vcpu *vcpu, int type, gva_t ea);
int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, gva_t ea);
int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500);
void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500);

+10 −4
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
	int ra = get_ra(inst);
	int rb = get_rb(inst);
	int rt = get_rt(inst);
	gva_t ea;

	switch (get_op(inst)) {
	case 31:
@@ -113,15 +114,20 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
			break;

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

		case XOP_TLBILX:
			emulated = kvmppc_e500_emul_tlbilx(vcpu, rt, ra, rb);
		case XOP_TLBILX: {
			int type = rt & 0x3;
			ea = kvmppc_get_ea_indexed(vcpu, ra, rb);
			emulated = kvmppc_e500_emul_tlbilx(vcpu, type, ea);
			break;
		}

		case XOP_TLBIVAX:
			emulated = kvmppc_e500_emul_tlbivax(vcpu, ra, rb);
			ea = kvmppc_get_ea_indexed(vcpu, ra, rb);
			emulated = kvmppc_e500_emul_tlbivax(vcpu, ea);
			break;

		default:
+11 −22
Original line number Diff line number Diff line
@@ -689,14 +689,11 @@ int kvmppc_e500_emul_mt_mmucsr0(struct kvmppc_vcpu_e500 *vcpu_e500, ulong value)
	return EMULATE_DONE;
}

int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, int ra, int rb)
int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, gva_t ea)
{
	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
	unsigned int ia;
	int esel, tlbsel;
	gva_t ea;

	ea = ((ra) ? kvmppc_get_gpr(vcpu, ra) : 0) + kvmppc_get_gpr(vcpu, rb);

	ia = (ea >> 2) & 0x1;

@@ -723,7 +720,7 @@ int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *vcpu, int ra, int rb)
}

static void tlbilx_all(struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel,
		       int pid, int rt)
		       int pid, int type)
{
	struct kvm_book3e_206_tlb_entry *tlbe;
	int tid, esel;
@@ -732,7 +729,7 @@ static void tlbilx_all(struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel,
	for (esel = 0; esel < vcpu_e500->gtlb_params[tlbsel].entries; esel++) {
		tlbe = get_entry(vcpu_e500, tlbsel, esel);
		tid = get_tlb_tid(tlbe);
		if (rt == 0 || tid == pid) {
		if (type == 0 || tid == pid) {
			inval_gtlbe_on_host(vcpu_e500, tlbsel, esel);
			kvmppc_e500_gtlbe_invalidate(vcpu_e500, tlbsel, esel);
		}
@@ -740,14 +737,9 @@ static void tlbilx_all(struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel,
}

static void tlbilx_one(struct kvmppc_vcpu_e500 *vcpu_e500, int pid,
		       int ra, int rb)
		       gva_t ea)
{
	int tlbsel, esel;
	gva_t ea;

	ea = kvmppc_get_gpr(&vcpu_e500->vcpu, rb);
	if (ra)
		ea += kvmppc_get_gpr(&vcpu_e500->vcpu, ra);

	for (tlbsel = 0; tlbsel < 2; tlbsel++) {
		esel = kvmppc_e500_tlb_index(vcpu_e500, ea, tlbsel, pid, -1);
@@ -759,16 +751,16 @@ static void tlbilx_one(struct kvmppc_vcpu_e500 *vcpu_e500, int pid,
	}
}

int kvmppc_e500_emul_tlbilx(struct kvm_vcpu *vcpu, int rt, int ra, int rb)
int kvmppc_e500_emul_tlbilx(struct kvm_vcpu *vcpu, int type, gva_t ea)
{
	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
	int pid = get_cur_spid(vcpu);

	if (rt == 0 || rt == 1) {
		tlbilx_all(vcpu_e500, 0, pid, rt);
		tlbilx_all(vcpu_e500, 1, pid, rt);
	} else if (rt == 3) {
		tlbilx_one(vcpu_e500, pid, ra, rb);
	if (type == 0 || type == 1) {
		tlbilx_all(vcpu_e500, 0, pid, type);
		tlbilx_all(vcpu_e500, 1, pid, type);
	} else if (type == 3) {
		tlbilx_one(vcpu_e500, pid, ea);
	}

	return EMULATE_DONE;
@@ -793,16 +785,13 @@ int kvmppc_e500_emul_tlbre(struct kvm_vcpu *vcpu)
	return EMULATE_DONE;
}

int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, int rb)
int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, gva_t ea)
{
	struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
	int as = !!get_cur_sas(vcpu);
	unsigned int pid = get_cur_spid(vcpu);
	int esel, tlbsel;
	struct kvm_book3e_206_tlb_entry *gtlbe = NULL;
	gva_t ea;

	ea = kvmppc_get_gpr(vcpu, rb);

	for (tlbsel = 0; tlbsel < 2; tlbsel++) {
		esel = kvmppc_e500_tlb_index(vcpu_e500, ea, tlbsel, pid, as);