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

Commit 8b23de29 authored by Paul Mackerras's avatar Paul Mackerras Committed by Alexander Graf
Browse files

KVM: PPC: Book3S PR: Make instruction fetch fallback work for system calls



It turns out that if we exit the guest due to a hcall instruction (sc 1),
and the loading of the instruction in the guest exit path fails for any
reason, the call to kvmppc_ld() in kvmppc_get_last_inst() fetches the
instruction after the hcall instruction rather than the hcall itself.
This in turn means that the instruction doesn't get recognized as an
hcall in kvmppc_handle_exit_pr() but gets passed to the guest kernel
as a sc instruction.  That usually results in the guest kernel getting
a return code of 38 (ENOSYS) from an hcall, which often triggers a
BUG_ON() or other failure.

This fixes the problem by adding a new variant of kvmppc_get_last_inst()
called kvmppc_get_last_sc(), which fetches the instruction if necessary
from pc - 4 rather than pc.

Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
Signed-off-by: default avatarAlexander Graf <agraf@suse.de>
parent 9d1ffdd8
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -334,6 +334,27 @@ static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu)
	return r;
}

/*
 * 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)
{
	ulong pc = kvmppc_get_pc(vcpu) - 4;
	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
	u32 r;

	/* Load the instruction manually if it failed to do so in the
	 * exit path */
	if (svcpu->last_inst == KVM_INST_FETCH_FAILED)
		kvmppc_ld(vcpu, &pc, sizeof(u32), &svcpu->last_inst, false);

	r = svcpu->last_inst;
	svcpu_put(svcpu);
	return r;
}

static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
{
	struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
@@ -446,6 +467,23 @@ static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu)
	return vcpu->arch.last_inst;
}

/*
 * 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)
{
	ulong pc = kvmppc_get_pc(vcpu) - 4;

	/* 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 vcpu->arch.last_inst;
}

static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
{
	return vcpu->arch.fault_dar;
+1 −1
Original line number Diff line number Diff line
@@ -792,7 +792,7 @@ program_interrupt:
	}
	case BOOK3S_INTERRUPT_SYSCALL:
		if (vcpu->arch.papr_enabled &&
		    (kvmppc_get_last_inst(vcpu) == 0x44000022) &&
		    (kvmppc_get_last_sc(vcpu) == 0x44000022) &&
		    !(vcpu->arch.shared->msr & MSR_PR)) {
			/* SC 1 papr hypercalls */
			ulong cmd = kvmppc_get_gpr(vcpu, 3);