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

Commit 97e96437 authored by Marc Zyngier's avatar Marc Zyngier
Browse files

ARM: KVM: Add populating of fault data structure



On guest exit, we must take care of populating our fault data
structure so that the host code can handle it. This includes
resolving the IPA for permission faults, which can result in
restarting the guest.

Reviewed-by: default avatarChristoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
parent 9dddc2df
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -76,10 +76,14 @@
#define IFSR		__ACCESS_CP15(c5, 0, c0, 1)
#define ADFSR		__ACCESS_CP15(c5, 0, c1, 0)
#define AIFSR		__ACCESS_CP15(c5, 0, c1, 1)
#define HSR		__ACCESS_CP15(c5, 4, c2, 0)
#define DFAR		__ACCESS_CP15(c6, 0, c0, 0)
#define IFAR		__ACCESS_CP15(c6, 0, c0, 2)
#define HDFAR		__ACCESS_CP15(c6, 4, c0, 0)
#define HIFAR		__ACCESS_CP15(c6, 4, c0, 2)
#define HPFAR		__ACCESS_CP15(c6, 4, c0, 4)
#define ICIALLUIS	__ACCESS_CP15(c7, 0, c1, 0)
#define ATS1CPR		__ACCESS_CP15(c7, 0, c8, 0)
#define TLBIALLIS	__ACCESS_CP15(c8, 0, c3, 0)
#define TLBIALLNSNHIS	__ACCESS_CP15(c8, 4, c3, 4)
#define PRRR		__ACCESS_CP15(c10, 0, c2, 0)
+54 −0
Original line number Diff line number Diff line
@@ -84,6 +84,56 @@ static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
	__vgic_v2_restore_state(vcpu);
}

static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu)
{
	u32 hsr = read_sysreg(HSR);
	u8 ec = hsr >> HSR_EC_SHIFT;
	u32 hpfar, far;

	vcpu->arch.fault.hsr = hsr;

	if (ec == HSR_EC_IABT)
		far = read_sysreg(HIFAR);
	else if (ec == HSR_EC_DABT)
		far = read_sysreg(HDFAR);
	else
		return true;

	/*
	 * B3.13.5 Reporting exceptions taken to the Non-secure PL2 mode:
	 *
	 * Abort on the stage 2 translation for a memory access from a
	 * Non-secure PL1 or PL0 mode:
	 *
	 * For any Access flag fault or Translation fault, and also for any
	 * Permission fault on the stage 2 translation of a memory access
	 * made as part of a translation table walk for a stage 1 translation,
	 * the HPFAR holds the IPA that caused the fault. Otherwise, the HPFAR
	 * is UNKNOWN.
	 */
	if (!(hsr & HSR_DABT_S1PTW) && (hsr & HSR_FSC_TYPE) == FSC_PERM) {
		u64 par, tmp;

		par = read_sysreg(PAR);
		write_sysreg(far, ATS1CPR);
		isb();

		tmp = read_sysreg(PAR);
		write_sysreg(par, PAR);

		if (unlikely(tmp & 1))
			return false; /* Translation failed, back to guest */

		hpfar = ((tmp >> 12) & ((1UL << 28) - 1)) << 4;
	} else {
		hpfar = read_sysreg(HPFAR);
	}

	vcpu->arch.fault.hxfar = far;
	vcpu->arch.fault.hpfar = hpfar;
	return true;
}

static int __hyp_text __guest_run(struct kvm_vcpu *vcpu)
{
	struct kvm_cpu_context *host_ctxt;
@@ -111,9 +161,13 @@ static int __hyp_text __guest_run(struct kvm_vcpu *vcpu)
	__banked_restore_state(guest_ctxt);

	/* Jump in the fire! */
again:
	exit_code = __guest_enter(vcpu, host_ctxt);
	/* And we're baaack! */

	if (exit_code == ARM_EXCEPTION_HVC && !__populate_fault_info(vcpu))
		goto again;

	fp_enabled = __vfp_enabled();

	__banked_save_state(guest_ctxt);