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

Commit 51f04726 authored by Mihai Caraman's avatar Mihai Caraman Committed by Alexander Graf
Browse files

KVM: PPC: Allow kvmppc_get_last_inst() to fail



On book3e, guest last instruction is read on the exit path using load
external pid (lwepx) dedicated instruction. This load operation may fail
due to TLB eviction and execute-but-not-read entries.

This patch lay down the path for an alternative solution to read the guest
last instruction, by allowing kvmppc_get_lat_inst() function to fail.
Architecture specific implmentations of kvmppc_load_last_inst() may read
last guest instruction and instruct the emulation layer to re-execute the
guest in case of failure.

Make kvmppc_get_last_inst() definition common between architectures.

Signed-off-by: default avatarMihai Caraman <mihai.caraman@freescale.com>
Signed-off-by: default avatarAlexander Graf <agraf@suse.de>
parent 9a26af64
Loading
Loading
Loading
Loading
+0 −26
Original line number Diff line number Diff line
@@ -276,32 +276,6 @@ static inline bool kvmppc_need_byteswap(struct kvm_vcpu *vcpu)
	return (kvmppc_get_msr(vcpu) & MSR_LE) != (MSR_KERNEL & MSR_LE);
}

static inline u32 kvmppc_get_last_inst_internal(struct kvm_vcpu *vcpu, ulong pc)
{
	/* Load the instruction manually if it failed to do so in the
	 * exit path */
	if (vcpu->arch.last_inst == KVM_INST_FETCH_FAILED)
		kvmppc_ld(vcpu, &pc, sizeof(u32), &vcpu->arch.last_inst, false);

	return kvmppc_need_byteswap(vcpu) ? swab32(vcpu->arch.last_inst) :
		vcpu->arch.last_inst;
}

static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu)
{
	return kvmppc_get_last_inst_internal(vcpu, kvmppc_get_pc(vcpu));
}

/*
 * Like kvmppc_get_last_inst(), but for fetching a sc instruction.
 * Because the sc instruction sets SRR0 to point to the following
 * instruction, we have to fetch from pc - 4.
 */
static inline u32 kvmppc_get_last_sc(struct kvm_vcpu *vcpu)
{
	return kvmppc_get_last_inst_internal(vcpu, kvmppc_get_pc(vcpu) - 4);
}

static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
{
	return vcpu->arch.fault_dar;
+0 −5
Original line number Diff line number Diff line
@@ -69,11 +69,6 @@ static inline bool kvmppc_need_byteswap(struct kvm_vcpu *vcpu)
	return false;
}

static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu)
{
	return vcpu->arch.last_inst;
}

static inline void kvmppc_set_ctr(struct kvm_vcpu *vcpu, ulong val)
{
	vcpu->arch.ctr = val;
+31 −0
Original line number Diff line number Diff line
@@ -47,6 +47,11 @@ enum emulation_result {
	EMULATE_EXIT_USER,    /* emulation requires exit to user-space */
};

enum instruction_type {
	INST_GENERIC,
	INST_SC,		/* system call */
};

extern int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
extern int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
extern void kvmppc_handler_highmem(void);
@@ -62,6 +67,9 @@ extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
			       u64 val, unsigned int bytes,
			       int is_default_endian);

extern int kvmppc_load_last_inst(struct kvm_vcpu *vcpu,
				 enum instruction_type type, u32 *inst);

extern int kvmppc_emulate_instruction(struct kvm_run *run,
                                      struct kvm_vcpu *vcpu);
extern int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu);
@@ -234,6 +242,29 @@ struct kvmppc_ops {
extern struct kvmppc_ops *kvmppc_hv_ops;
extern struct kvmppc_ops *kvmppc_pr_ops;

static inline int kvmppc_get_last_inst(struct kvm_vcpu *vcpu,
					enum instruction_type type, u32 *inst)
{
	int ret = EMULATE_DONE;
	u32 fetched_inst;

	/* Load the instruction manually if it failed to do so in the
	 * exit path */
	if (vcpu->arch.last_inst == KVM_INST_FETCH_FAILED)
		ret = kvmppc_load_last_inst(vcpu, type, &vcpu->arch.last_inst);

	/*  Write fetch_failed unswapped if the fetch failed */
	if (ret == EMULATE_DONE)
		fetched_inst = kvmppc_need_byteswap(vcpu) ?
				swab32(vcpu->arch.last_inst) :
				vcpu->arch.last_inst;
	else
		fetched_inst = vcpu->arch.last_inst;

	*inst = fetched_inst;
	return ret;
}

static inline bool is_kvmppc_hv_enabled(struct kvm *kvm)
{
	return kvm->arch.kvm_ops == kvmppc_hv_ops;
+17 −0
Original line number Diff line number Diff line
@@ -488,6 +488,23 @@ int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr,
}
EXPORT_SYMBOL_GPL(kvmppc_ld);

int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, enum instruction_type type,
					 u32 *inst)
{
	ulong pc = kvmppc_get_pc(vcpu);
	int r;

	if (type == INST_SC)
		pc -= 4;

	r = kvmppc_ld(vcpu, &pc, sizeof(u32), inst, false);
	if (r == EMULATE_DONE)
		return r;
	else
		return EMULATE_AGAIN;
}
EXPORT_SYMBOL_GPL(kvmppc_load_last_inst);

int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
{
	return 0;
+5 −12
Original line number Diff line number Diff line
@@ -530,21 +530,14 @@ static int instruction_is_store(unsigned int instr)
static int kvmppc_hv_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu,
				  unsigned long gpa, gva_t ea, int is_store)
{
	int ret;
	u32 last_inst;
	unsigned long srr0 = kvmppc_get_pc(vcpu);

	/* We try to load the last instruction.  We don't let
	 * emulate_instruction do it as it doesn't check what
	 * kvmppc_ld returns.
	/*
	 * If we fail, we just return to the guest and try executing it again.
	 */
	if (vcpu->arch.last_inst == KVM_INST_FETCH_FAILED) {
		ret = kvmppc_ld(vcpu, &srr0, sizeof(u32), &last_inst, false);
		if (ret != EMULATE_DONE || last_inst == KVM_INST_FETCH_FAILED)
	if (kvmppc_get_last_inst(vcpu, INST_GENERIC, &last_inst) !=
		EMULATE_DONE)
		return RESUME_GUEST;
		vcpu->arch.last_inst = last_inst;
	}

	/*
	 * WARNING: We do not know for sure whether the instruction we just
@@ -558,7 +551,7 @@ static int kvmppc_hv_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu,
	 * we just return and retry the instruction.
	 */

	if (instruction_is_store(kvmppc_get_last_inst(vcpu)) != !!is_store)
	if (instruction_is_store(last_inst) != !!is_store)
		return RESUME_GUEST;

	/*
Loading