]> git.karo-electronics.de Git - linux-beck.git/commitdiff
ARM: KVM: Add populating of fault data structure
authorMarc Zyngier <marc.zyngier@arm.com>
Wed, 13 Jan 2016 19:02:51 +0000 (19:02 +0000)
committerMarc Zyngier <marc.zyngier@arm.com>
Mon, 29 Feb 2016 18:34:14 +0000 (18:34 +0000)
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: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
arch/arm/kvm/hyp/hyp.h
arch/arm/kvm/hyp/switch.c

index ef582c9ad96d8b5d49637210f50e4f1eeb09d25e..8b1156b691ff2c556d2f491032f4a74ab8ba790c 100644 (file)
 #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)
index a1f3c1cf8f74652e541daa991786915eab708578..0dd0ba33b8a759c02c2a2e8d86c3def88fd3ed07 100644 (file)
@@ -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);