All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/19] Handle guest-generated SErrors/Aborts
@ 2016-09-06 13:01 ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:01 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: kvm, linux-arm-kernel, kvmarm

A little known "feature" of giving guest access to real memory mapped
HW is that it could trigger asynchronous aborts (SError on ARMv8) if
the guest accesses it in a non-conventional way (and depending on how
HW and firmware have been integrated). So far, KVM lacks any support
to handle this gracefully.

This series introduces a set of mechanisms to catch such a fault and
deliver a vSError (or Virtual Abort for 32bit) to the offending vcpu.

These aborts can either trigger at EL1 (whilst the guest is running),
or at EL2 (during the handling of an exit). The first case is pretty
easy to handle (use the ad-hoc vectors on arm64, or decode the EA bit
on arm), but the second one is a bit more fiddly, as we need to ensure
that the exception is pending by the time we unmask it. This is
achived by using some heavy DSBs on the hot path, with the following
caveats:

- I've only been able to trigger the EL2 handling on A57 (Seatle,
  Juno).
- I've measured a 40/50 cycles hit on Juno (A57), but I haven't
  measured the impact on bigger systems

The last patch of this series adds a missing feature to the
GICV-proxying series, delivering a vSError to a guest that performed
an illegal access to the GIC.

Patches on top of current kvmarm/queue + the GICV przying series.

Marc Zyngier (19):
  arm64: KVM: Rename HCR_VA to HCR_VSE
  arm64: KVM: Preserve pending vSError in world switch
  arm64: KVM: Add Virtual Abort injection helper
  arm64: KVM: Add exception code to report EL1 asynchronous aborts
  arm64: KVM: Add EL1 async abort handler
  arm64: KVM: Route asynchronous aborts
  arm64: KVM: Allow an exit code to be tagged with an SError
  arm64: KVM: Inject a Virtual SError if it was pending
  arm64: KVM: Handle async aborts delivered while at EL2
  arm: KVM: Preserve pending Virtual Abort in world switch
  arm: KVM: Add Virtual Abort injection helper
  arm: KVM: Add HYP async abort handler
  arm: KVM: Allow an exit code to be tagged with a Virtual Abort
  arm: KVM: Handle async aborts delivered while at HYP
  arm: KVM: Inject a Virtual Abort if it was pending
  arm: KVM: Drop unreachable HYP abort handlers
  arm/arm64: KVM: Inject virtual abort when guest exits on external
    abort
  arm/arm64: KVM: Remove external abort test from MMIO handling
  arm64: KVM: Inject a vSerror if detecting a bad GICV access at EL2

 arch/arm/include/asm/kvm_asm.h       |  4 +++
 arch/arm/include/asm/kvm_emulate.h   |  1 +
 arch/arm/kvm/emulate.c               | 12 +++++++++
 arch/arm/kvm/handle_exit.c           | 49 ++++++++++++++++--------------------
 arch/arm/kvm/hyp/entry.S             | 31 +++++++++++++++++++++++
 arch/arm/kvm/hyp/hyp-entry.S         | 16 +++++++++++-
 arch/arm/kvm/hyp/switch.c            |  9 +++++++
 arch/arm/kvm/mmio.c                  |  6 -----
 arch/arm/kvm/mmu.c                   |  5 ++++
 arch/arm64/include/asm/kvm_arm.h     |  4 +--
 arch/arm64/include/asm/kvm_asm.h     |  9 +++++--
 arch/arm64/include/asm/kvm_emulate.h |  1 +
 arch/arm64/include/asm/kvm_hyp.h     |  2 +-
 arch/arm64/kvm/handle_exit.c         | 23 +++++++++++++++++
 arch/arm64/kvm/hyp/entry.S           | 33 +++++++++++++++++++++++-
 arch/arm64/kvm/hyp/hyp-entry.S       | 36 ++++++++++++++++++++++----
 arch/arm64/kvm/hyp/switch.c          | 33 +++++++++++++++++++++---
 arch/arm64/kvm/inject_fault.c        | 12 +++++++++
 virt/kvm/arm/hyp/vgic-v2-sr.c        | 21 ++++++++++++----
 19 files changed, 254 insertions(+), 53 deletions(-)

-- 
2.1.4

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 00/19] Handle guest-generated SErrors/Aborts
@ 2016-09-06 13:01 ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:01 UTC (permalink / raw)
  To: linux-arm-kernel

A little known "feature" of giving guest access to real memory mapped
HW is that it could trigger asynchronous aborts (SError on ARMv8) if
the guest accesses it in a non-conventional way (and depending on how
HW and firmware have been integrated). So far, KVM lacks any support
to handle this gracefully.

This series introduces a set of mechanisms to catch such a fault and
deliver a vSError (or Virtual Abort for 32bit) to the offending vcpu.

These aborts can either trigger at EL1 (whilst the guest is running),
or at EL2 (during the handling of an exit). The first case is pretty
easy to handle (use the ad-hoc vectors on arm64, or decode the EA bit
on arm), but the second one is a bit more fiddly, as we need to ensure
that the exception is pending by the time we unmask it. This is
achived by using some heavy DSBs on the hot path, with the following
caveats:

- I've only been able to trigger the EL2 handling on A57 (Seatle,
  Juno).
- I've measured a 40/50 cycles hit on Juno (A57), but I haven't
  measured the impact on bigger systems

The last patch of this series adds a missing feature to the
GICV-proxying series, delivering a vSError to a guest that performed
an illegal access to the GIC.

Patches on top of current kvmarm/queue + the GICV przying series.

Marc Zyngier (19):
  arm64: KVM: Rename HCR_VA to HCR_VSE
  arm64: KVM: Preserve pending vSError in world switch
  arm64: KVM: Add Virtual Abort injection helper
  arm64: KVM: Add exception code to report EL1 asynchronous aborts
  arm64: KVM: Add EL1 async abort handler
  arm64: KVM: Route asynchronous aborts
  arm64: KVM: Allow an exit code to be tagged with an SError
  arm64: KVM: Inject a Virtual SError if it was pending
  arm64: KVM: Handle async aborts delivered while at EL2
  arm: KVM: Preserve pending Virtual Abort in world switch
  arm: KVM: Add Virtual Abort injection helper
  arm: KVM: Add HYP async abort handler
  arm: KVM: Allow an exit code to be tagged with a Virtual Abort
  arm: KVM: Handle async aborts delivered while at HYP
  arm: KVM: Inject a Virtual Abort if it was pending
  arm: KVM: Drop unreachable HYP abort handlers
  arm/arm64: KVM: Inject virtual abort when guest exits on external
    abort
  arm/arm64: KVM: Remove external abort test from MMIO handling
  arm64: KVM: Inject a vSerror if detecting a bad GICV access at EL2

 arch/arm/include/asm/kvm_asm.h       |  4 +++
 arch/arm/include/asm/kvm_emulate.h   |  1 +
 arch/arm/kvm/emulate.c               | 12 +++++++++
 arch/arm/kvm/handle_exit.c           | 49 ++++++++++++++++--------------------
 arch/arm/kvm/hyp/entry.S             | 31 +++++++++++++++++++++++
 arch/arm/kvm/hyp/hyp-entry.S         | 16 +++++++++++-
 arch/arm/kvm/hyp/switch.c            |  9 +++++++
 arch/arm/kvm/mmio.c                  |  6 -----
 arch/arm/kvm/mmu.c                   |  5 ++++
 arch/arm64/include/asm/kvm_arm.h     |  4 +--
 arch/arm64/include/asm/kvm_asm.h     |  9 +++++--
 arch/arm64/include/asm/kvm_emulate.h |  1 +
 arch/arm64/include/asm/kvm_hyp.h     |  2 +-
 arch/arm64/kvm/handle_exit.c         | 23 +++++++++++++++++
 arch/arm64/kvm/hyp/entry.S           | 33 +++++++++++++++++++++++-
 arch/arm64/kvm/hyp/hyp-entry.S       | 36 ++++++++++++++++++++++----
 arch/arm64/kvm/hyp/switch.c          | 33 +++++++++++++++++++++---
 arch/arm64/kvm/inject_fault.c        | 12 +++++++++
 virt/kvm/arm/hyp/vgic-v2-sr.c        | 21 ++++++++++++----
 19 files changed, 254 insertions(+), 53 deletions(-)

-- 
2.1.4

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 01/19] arm64: KVM: Rename HCR_VA to HCR_VSE
  2016-09-06 13:01 ` Marc Zyngier
@ 2016-09-06 13:01   ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:01 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: kvm, linux-arm-kernel, kvmarm

HCR_VA is a leftover from ARMv7, On ARMv8, this is HCR_VSE
(which stands for Virtual System Error), and has better
defined semantics.

Let's rename the constant.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/kvm_arm.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 4b5c977..2a2752b 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -50,7 +50,7 @@
 #define HCR_BSU		(3 << 10)
 #define HCR_BSU_IS	(UL(1) << 10)
 #define HCR_FB		(UL(1) << 9)
-#define HCR_VA		(UL(1) << 8)
+#define HCR_VSE		(UL(1) << 8)
 #define HCR_VI		(UL(1) << 7)
 #define HCR_VF		(UL(1) << 6)
 #define HCR_AMO		(UL(1) << 5)
@@ -80,7 +80,7 @@
 #define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \
 			 HCR_TVM | HCR_BSU_IS | HCR_FB | HCR_TAC | \
 			 HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW)
-#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
+#define HCR_VIRT_EXCP_MASK (HCR_VSE | HCR_VI | HCR_VF)
 #define HCR_INT_OVERRIDE   (HCR_FMO | HCR_IMO)
 #define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H)
 
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 01/19] arm64: KVM: Rename HCR_VA to HCR_VSE
@ 2016-09-06 13:01   ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:01 UTC (permalink / raw)
  To: linux-arm-kernel

HCR_VA is a leftover from ARMv7, On ARMv8, this is HCR_VSE
(which stands for Virtual System Error), and has better
defined semantics.

Let's rename the constant.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/kvm_arm.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 4b5c977..2a2752b 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -50,7 +50,7 @@
 #define HCR_BSU		(3 << 10)
 #define HCR_BSU_IS	(UL(1) << 10)
 #define HCR_FB		(UL(1) << 9)
-#define HCR_VA		(UL(1) << 8)
+#define HCR_VSE		(UL(1) << 8)
 #define HCR_VI		(UL(1) << 7)
 #define HCR_VF		(UL(1) << 6)
 #define HCR_AMO		(UL(1) << 5)
@@ -80,7 +80,7 @@
 #define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \
 			 HCR_TVM | HCR_BSU_IS | HCR_FB | HCR_TAC | \
 			 HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW)
-#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
+#define HCR_VIRT_EXCP_MASK (HCR_VSE | HCR_VI | HCR_VF)
 #define HCR_INT_OVERRIDE   (HCR_FMO | HCR_IMO)
 #define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H)
 
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 02/19] arm64: KVM: Preserve pending vSError in world switch
  2016-09-06 13:01 ` Marc Zyngier
@ 2016-09-06 13:02   ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: kvm, linux-arm-kernel, kvmarm

The HCR_EL2.VSE bit is used to signal an SError to a guest, and has
the peculiar feature of getting cleared when the guest has taken
the abort (this is the only bit that behaves as such in this register).

This means that if we signal such an abort, we must leave it
in the guest context until it disappears from HCR_EL2, and at which
point it must be cleared from the context. This is achieved by
reading back from HCR_EL2 until the guest takes the fault.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/kvm/hyp/switch.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index fcb7aae..5148b06 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -110,6 +110,15 @@ static hyp_alternate_select(__deactivate_traps_arch,
 
 static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
 {
+	/*
+	 * If we pended a virtual abort, preserve it until it gets
+	 * cleared. See D1.14.3 (Virtual Interrupts) for details, but
+	 * the crucial bit is "On taking a vSError interrupt,
+	 * HCR_EL2.VSE is cleared to 0."
+	 */
+	if (vcpu->arch.hcr_el2 & HCR_VSE)
+		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
+
 	__deactivate_traps_arch()();
 	write_sysreg(0, hstr_el2);
 	write_sysreg(read_sysreg(mdcr_el2) & MDCR_EL2_HPMN_MASK, mdcr_el2);
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 02/19] arm64: KVM: Preserve pending vSError in world switch
@ 2016-09-06 13:02   ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: linux-arm-kernel

The HCR_EL2.VSE bit is used to signal an SError to a guest, and has
the peculiar feature of getting cleared when the guest has taken
the abort (this is the only bit that behaves as such in this register).

This means that if we signal such an abort, we must leave it
in the guest context until it disappears from HCR_EL2, and at which
point it must be cleared from the context. This is achieved by
reading back from HCR_EL2 until the guest takes the fault.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/kvm/hyp/switch.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index fcb7aae..5148b06 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -110,6 +110,15 @@ static hyp_alternate_select(__deactivate_traps_arch,
 
 static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
 {
+	/*
+	 * If we pended a virtual abort, preserve it until it gets
+	 * cleared. See D1.14.3 (Virtual Interrupts) for details, but
+	 * the crucial bit is "On taking a vSError interrupt,
+	 * HCR_EL2.VSE is cleared to 0."
+	 */
+	if (vcpu->arch.hcr_el2 & HCR_VSE)
+		vcpu->arch.hcr_el2 = read_sysreg(hcr_el2);
+
 	__deactivate_traps_arch()();
 	write_sysreg(0, hstr_el2);
 	write_sysreg(read_sysreg(mdcr_el2) & MDCR_EL2_HPMN_MASK, mdcr_el2);
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 03/19] arm64: KVM: Add Virtual Abort injection helper
  2016-09-06 13:01 ` Marc Zyngier
@ 2016-09-06 13:02   ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: kvm, linux-arm-kernel, kvmarm

Now that we're able to context switch the HCR_EL2.VA bit, let's
introduce a helper that injects an Abort into a vcpu.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/kvm_emulate.h |  1 +
 arch/arm64/kvm/inject_fault.c        | 12 ++++++++++++
 2 files changed, 13 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index b336434d..fd9d5fd 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -38,6 +38,7 @@ bool kvm_condition_valid32(const struct kvm_vcpu *vcpu);
 void kvm_skip_instr32(struct kvm_vcpu *vcpu, bool is_wide_instr);
 
 void kvm_inject_undefined(struct kvm_vcpu *vcpu);
+void kvm_inject_vabt(struct kvm_vcpu *vcpu);
 void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
 void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
 
diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index 898c0e6..da6a8cf 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -231,3 +231,15 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu)
 	else
 		inject_undef64(vcpu);
 }
+
+/**
+ * kvm_inject_vabt - inject an async abort / SError into the guest
+ * @vcpu: The VCPU to receive the exception
+ *
+ * It is assumed that this code is called from the VCPU thread and that the
+ * VCPU therefore is not currently executing guest code.
+ */
+void kvm_inject_vabt(struct kvm_vcpu *vcpu)
+{
+	vcpu_set_hcr(vcpu, vcpu_get_hcr(vcpu) | HCR_VSE);
+}
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 03/19] arm64: KVM: Add Virtual Abort injection helper
@ 2016-09-06 13:02   ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: linux-arm-kernel

Now that we're able to context switch the HCR_EL2.VA bit, let's
introduce a helper that injects an Abort into a vcpu.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/kvm_emulate.h |  1 +
 arch/arm64/kvm/inject_fault.c        | 12 ++++++++++++
 2 files changed, 13 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index b336434d..fd9d5fd 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -38,6 +38,7 @@ bool kvm_condition_valid32(const struct kvm_vcpu *vcpu);
 void kvm_skip_instr32(struct kvm_vcpu *vcpu, bool is_wide_instr);
 
 void kvm_inject_undefined(struct kvm_vcpu *vcpu);
+void kvm_inject_vabt(struct kvm_vcpu *vcpu);
 void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
 void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
 
diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index 898c0e6..da6a8cf 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -231,3 +231,15 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu)
 	else
 		inject_undef64(vcpu);
 }
+
+/**
+ * kvm_inject_vabt - inject an async abort / SError into the guest
+ * @vcpu: The VCPU to receive the exception
+ *
+ * It is assumed that this code is called from the VCPU thread and that the
+ * VCPU therefore is not currently executing guest code.
+ */
+void kvm_inject_vabt(struct kvm_vcpu *vcpu)
+{
+	vcpu_set_hcr(vcpu, vcpu_get_hcr(vcpu) | HCR_VSE);
+}
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 04/19] arm64: KVM: Add exception code to report EL1 asynchronous aborts
  2016-09-06 13:01 ` Marc Zyngier
@ 2016-09-06 13:02   ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: linux-arm-kernel, kvm, kvmarm

So far, we don't have a code to indicate that we've taken an
asynchronous abort from EL1. Let's add one.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/kvm_asm.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 7561f63..d177e7e 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -21,9 +21,10 @@
 #include <asm/virt.h>
 
 #define ARM_EXCEPTION_IRQ	  0
-#define ARM_EXCEPTION_TRAP	  1
+#define ARM_EXCEPTION_EL1_SERROR  1
+#define ARM_EXCEPTION_TRAP	  2
 /* The hyp-stub will return this for any kvm_call_hyp() call */
-#define ARM_EXCEPTION_HYP_GONE	  2
+#define ARM_EXCEPTION_HYP_GONE	  3
 
 #define KVM_ARM64_DEBUG_DIRTY_SHIFT	0
 #define KVM_ARM64_DEBUG_DIRTY		(1 << KVM_ARM64_DEBUG_DIRTY_SHIFT)
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 04/19] arm64: KVM: Add exception code to report EL1 asynchronous aborts
@ 2016-09-06 13:02   ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: linux-arm-kernel

So far, we don't have a code to indicate that we've taken an
asynchronous abort from EL1. Let's add one.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/kvm_asm.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 7561f63..d177e7e 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -21,9 +21,10 @@
 #include <asm/virt.h>
 
 #define ARM_EXCEPTION_IRQ	  0
-#define ARM_EXCEPTION_TRAP	  1
+#define ARM_EXCEPTION_EL1_SERROR  1
+#define ARM_EXCEPTION_TRAP	  2
 /* The hyp-stub will return this for any kvm_call_hyp() call */
-#define ARM_EXCEPTION_HYP_GONE	  2
+#define ARM_EXCEPTION_HYP_GONE	  3
 
 #define KVM_ARM64_DEBUG_DIRTY_SHIFT	0
 #define KVM_ARM64_DEBUG_DIRTY		(1 << KVM_ARM64_DEBUG_DIRTY_SHIFT)
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 05/19] arm64: KVM: Add EL1 async abort handler
  2016-09-06 13:01 ` Marc Zyngier
@ 2016-09-06 13:02   ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: linux-arm-kernel, kvm, kvmarm

If we've exited the guest because it has triggered an asynchronous
abort from EL1, a possible course of action is to let it know it
screwed up by giving it a Virtual Abort to chew on.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/kvm/handle_exit.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index fa96fe2b..08afc69a 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -173,6 +173,9 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
 	switch (exception_index) {
 	case ARM_EXCEPTION_IRQ:
 		return 1;
+	case ARM_EXCEPTION_EL1_SERROR:
+		kvm_inject_vabt(vcpu);
+		return 1;
 	case ARM_EXCEPTION_TRAP:
 		/*
 		 * See ARM ARM B1.14.1: "Hyp traps on instructions
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 05/19] arm64: KVM: Add EL1 async abort handler
@ 2016-09-06 13:02   ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: linux-arm-kernel

If we've exited the guest because it has triggered an asynchronous
abort from EL1, a possible course of action is to let it know it
screwed up by giving it a Virtual Abort to chew on.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/kvm/handle_exit.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index fa96fe2b..08afc69a 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -173,6 +173,9 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
 	switch (exception_index) {
 	case ARM_EXCEPTION_IRQ:
 		return 1;
+	case ARM_EXCEPTION_EL1_SERROR:
+		kvm_inject_vabt(vcpu);
+		return 1;
 	case ARM_EXCEPTION_TRAP:
 		/*
 		 * See ARM ARM B1.14.1: "Hyp traps on instructions
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 06/19] arm64: KVM: Route asynchronous aborts
  2016-09-06 13:01 ` Marc Zyngier
@ 2016-09-06 13:02   ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: kvm, linux-arm-kernel, kvmarm

As we now have some basic handling to EL1-triggered aborts, we can
actually report them to KVM.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/kvm/hyp/hyp-entry.S | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
index d6cae54..d2f6640 100644
--- a/arch/arm64/kvm/hyp/hyp-entry.S
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -120,6 +120,12 @@ el1_irq:
 	mov	x0, #ARM_EXCEPTION_IRQ
 	b	__guest_exit
 
+el1_error:
+	stp     x0, x1, [sp, #-16]!
+	mrs	x1, tpidr_el2
+	mov	x0, #ARM_EXCEPTION_EL1_SERROR
+	b	__guest_exit
+
 ENTRY(__hyp_do_panic)
 	mov	lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
 		      PSR_MODE_EL1h)
@@ -148,7 +154,6 @@ ENDPROC(\label)
 	invalid_vector	el1_sync_invalid
 	invalid_vector	el1_irq_invalid
 	invalid_vector	el1_fiq_invalid
-	invalid_vector	el1_error_invalid
 
 	.ltorg
 
@@ -168,10 +173,10 @@ ENTRY(__kvm_hyp_vector)
 	ventry	el1_sync			// Synchronous 64-bit EL1
 	ventry	el1_irq				// IRQ 64-bit EL1
 	ventry	el1_fiq_invalid			// FIQ 64-bit EL1
-	ventry	el1_error_invalid		// Error 64-bit EL1
+	ventry	el1_error			// Error 64-bit EL1
 
 	ventry	el1_sync			// Synchronous 32-bit EL1
 	ventry	el1_irq				// IRQ 32-bit EL1
 	ventry	el1_fiq_invalid			// FIQ 32-bit EL1
-	ventry	el1_error_invalid		// Error 32-bit EL1
+	ventry	el1_error			// Error 32-bit EL1
 ENDPROC(__kvm_hyp_vector)
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 06/19] arm64: KVM: Route asynchronous aborts
@ 2016-09-06 13:02   ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: linux-arm-kernel

As we now have some basic handling to EL1-triggered aborts, we can
actually report them to KVM.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/kvm/hyp/hyp-entry.S | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
index d6cae54..d2f6640 100644
--- a/arch/arm64/kvm/hyp/hyp-entry.S
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -120,6 +120,12 @@ el1_irq:
 	mov	x0, #ARM_EXCEPTION_IRQ
 	b	__guest_exit
 
+el1_error:
+	stp     x0, x1, [sp, #-16]!
+	mrs	x1, tpidr_el2
+	mov	x0, #ARM_EXCEPTION_EL1_SERROR
+	b	__guest_exit
+
 ENTRY(__hyp_do_panic)
 	mov	lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
 		      PSR_MODE_EL1h)
@@ -148,7 +154,6 @@ ENDPROC(\label)
 	invalid_vector	el1_sync_invalid
 	invalid_vector	el1_irq_invalid
 	invalid_vector	el1_fiq_invalid
-	invalid_vector	el1_error_invalid
 
 	.ltorg
 
@@ -168,10 +173,10 @@ ENTRY(__kvm_hyp_vector)
 	ventry	el1_sync			// Synchronous 64-bit EL1
 	ventry	el1_irq				// IRQ 64-bit EL1
 	ventry	el1_fiq_invalid			// FIQ 64-bit EL1
-	ventry	el1_error_invalid		// Error 64-bit EL1
+	ventry	el1_error			// Error 64-bit EL1
 
 	ventry	el1_sync			// Synchronous 32-bit EL1
 	ventry	el1_irq				// IRQ 32-bit EL1
 	ventry	el1_fiq_invalid			// FIQ 32-bit EL1
-	ventry	el1_error_invalid		// Error 32-bit EL1
+	ventry	el1_error			// Error 32-bit EL1
 ENDPROC(__kvm_hyp_vector)
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 07/19] arm64: KVM: Allow an exit code to be tagged with an SError
  2016-09-06 13:01 ` Marc Zyngier
@ 2016-09-06 13:02   ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: linux-arm-kernel, kvm, kvmarm

Similarily to EL1, an asynchronous abort can be triggered whilst
running at EL2. But instead of making that a new error code,
we need to communicate it to the rest of KVM together with
the exit reason. So let's hijack a single bit that allows the
exception code to be tagged with a "pending SError" information.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/kvm_asm.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index d177e7e..18f7465 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -20,6 +20,10 @@
 
 #include <asm/virt.h>
 
+#define ARM_EXIT_WITH_SERROR_BIT  31
+#define ARM_EXCEPTION_CODE(x)	  ((x) & ~(1U << ARM_EXIT_WITH_SERROR_BIT))
+#define ARM_SERROR_PENDING(x)	  !!((x) & (1U << ARM_EXIT_WITH_SERROR_BIT))
+
 #define ARM_EXCEPTION_IRQ	  0
 #define ARM_EXCEPTION_EL1_SERROR  1
 #define ARM_EXCEPTION_TRAP	  2
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 07/19] arm64: KVM: Allow an exit code to be tagged with an SError
@ 2016-09-06 13:02   ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: linux-arm-kernel

Similarily to EL1, an asynchronous abort can be triggered whilst
running at EL2. But instead of making that a new error code,
we need to communicate it to the rest of KVM together with
the exit reason. So let's hijack a single bit that allows the
exception code to be tagged with a "pending SError" information.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/kvm_asm.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index d177e7e..18f7465 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -20,6 +20,10 @@
 
 #include <asm/virt.h>
 
+#define ARM_EXIT_WITH_SERROR_BIT  31
+#define ARM_EXCEPTION_CODE(x)	  ((x) & ~(1U << ARM_EXIT_WITH_SERROR_BIT))
+#define ARM_SERROR_PENDING(x)	  !!((x) & (1U << ARM_EXIT_WITH_SERROR_BIT))
+
 #define ARM_EXCEPTION_IRQ	  0
 #define ARM_EXCEPTION_EL1_SERROR  1
 #define ARM_EXCEPTION_TRAP	  2
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 08/19] arm64: KVM: Inject a Virtual SError if it was pending
  2016-09-06 13:01 ` Marc Zyngier
@ 2016-09-06 13:02   ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: kvm, linux-arm-kernel, kvmarm

If we have caught an SError whilst exiting, we've tagged the
exit code with the pending information. In that case, let's
re-inject the error into the guest, after having adjusted
the PC if required.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/kvm/handle_exit.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 08afc69a..a204adf 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -170,6 +170,26 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
 {
 	exit_handle_fn exit_handler;
 
+	if (ARM_SERROR_PENDING(exception_index)) {
+		u8 hsr_ec = ESR_ELx_EC(kvm_vcpu_get_hsr(vcpu));
+
+		/*
+		 * HVC/SMC already have an adjusted PC, which we need
+		 * to correct in order to return to after having
+		 * injected the SError.
+		 */
+		if (hsr_ec == ESR_ELx_EC_HVC32 || hsr_ec == ESR_ELx_EC_HVC64 ||
+		    hsr_ec == ESR_ELx_EC_SMC32 || hsr_ec == ESR_ELx_EC_SMC64) {
+			u32 adj =  kvm_vcpu_trap_il_is32bit(vcpu) ? 4 : 2;
+			*vcpu_pc(vcpu) -= adj;
+		}
+
+		kvm_inject_vabt(vcpu);
+		return 1;
+	}
+
+	exception_index = ARM_EXCEPTION_CODE(exception_index);
+
 	switch (exception_index) {
 	case ARM_EXCEPTION_IRQ:
 		return 1;
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 08/19] arm64: KVM: Inject a Virtual SError if it was pending
@ 2016-09-06 13:02   ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: linux-arm-kernel

If we have caught an SError whilst exiting, we've tagged the
exit code with the pending information. In that case, let's
re-inject the error into the guest, after having adjusted
the PC if required.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/kvm/handle_exit.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 08afc69a..a204adf 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -170,6 +170,26 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
 {
 	exit_handle_fn exit_handler;
 
+	if (ARM_SERROR_PENDING(exception_index)) {
+		u8 hsr_ec = ESR_ELx_EC(kvm_vcpu_get_hsr(vcpu));
+
+		/*
+		 * HVC/SMC already have an adjusted PC, which we need
+		 * to correct in order to return to after having
+		 * injected the SError.
+		 */
+		if (hsr_ec == ESR_ELx_EC_HVC32 || hsr_ec == ESR_ELx_EC_HVC64 ||
+		    hsr_ec == ESR_ELx_EC_SMC32 || hsr_ec == ESR_ELx_EC_SMC64) {
+			u32 adj =  kvm_vcpu_trap_il_is32bit(vcpu) ? 4 : 2;
+			*vcpu_pc(vcpu) -= adj;
+		}
+
+		kvm_inject_vabt(vcpu);
+		return 1;
+	}
+
+	exception_index = ARM_EXCEPTION_CODE(exception_index);
+
 	switch (exception_index) {
 	case ARM_EXCEPTION_IRQ:
 		return 1;
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 09/19] arm64: KVM: Handle async aborts delivered while at EL2
  2016-09-06 13:01 ` Marc Zyngier
@ 2016-09-06 13:02   ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: linux-arm-kernel, kvm, kvmarm

If EL1 generates an asynchronous abort and then traps into EL2
before the abort has been delivered, we may end-up with the
abort firing at the worse possible place: on the host.

In order to avoid this, it is necessary to take the abort at EL2,
by clearing the PSTATE.A bit. In order to survive this abort,
we do it at a point where we're in a known state with respect
to the world switch, and handle the resulting exception,
overloading the exit code in the process.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/kvm/hyp/entry.S     | 33 ++++++++++++++++++++++++++++++++-
 arch/arm64/kvm/hyp/hyp-entry.S | 25 +++++++++++++++++++++++--
 arch/arm64/kvm/hyp/switch.c    |  6 ++++++
 3 files changed, 61 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
index 3967c231..7662ef5 100644
--- a/arch/arm64/kvm/hyp/entry.S
+++ b/arch/arm64/kvm/hyp/entry.S
@@ -122,7 +122,38 @@ ENTRY(__guest_exit)
 	// Now restore the host regs
 	restore_callee_saved_regs x2
 
-	ret
+	// If we have a pending asynchronous abort, now is the
+	// time to find out. From your VAXorcist book, page 666:
+	// "Threaten me not, oh Evil one!  For I speak with
+	// the power of DEC, and I command thee to show thyself!"
+	mrs	x2, elr_el2
+	mrs	x3, esr_el2
+	mrs	x4, spsr_el2
+	mov	x5, x0
+
+	dsb	sy		// Synchronize against in-flight ld/st
+	msr	daifclr, #4	// Unmask aborts
+
+	// This is our single instruction exception window. A pending
+	// SError is guaranteed to occur at the earliest when we unmask
+	// it, and at the latest just after the ISB.
+	.global	abort_guest_exit_start
+abort_guest_exit_start:
+
+	isb
+
+	.global	abort_guest_exit_end
+abort_guest_exit_end:
+
+	// If the exception took place, restore the EL1 exception
+	// context so that we can report some information.
+	// Merge the exception code with the SError pending bit.
+	tbz	x0, #ARM_EXIT_WITH_SERROR_BIT, 1f
+	msr	elr_el2, x2
+	msr	esr_el2, x3
+	msr	spsr_el2, x4
+	orr	x0, x0, x5
+1:	ret
 ENDPROC(__guest_exit)
 
 ENTRY(__fpsimd_guest_restore)
diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
index d2f6640..4e92399 100644
--- a/arch/arm64/kvm/hyp/hyp-entry.S
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -126,6 +126,28 @@ el1_error:
 	mov	x0, #ARM_EXCEPTION_EL1_SERROR
 	b	__guest_exit
 
+el2_error:
+	/*
+	 * Only two possibilities:
+	 * 1) Either we come from the exit path, having just unmasked
+	 *    PSTATE.A: change the return code to an EL2 fault, and
+	 *    carry on, as we're already in a sane state to handle it.
+	 * 2) Or we come from anywhere else, and that's a bug: we panic.
+	 *
+	 * For (1), x0 contains the original return code and x1 doesn't
+	 * contain anything meaningful at that stage. We can reuse them
+	 * as temp registers.
+	 * For (2), who cares?
+	 */
+	mrs	x0, elr_el2
+	adr	x1, abort_guest_exit_start
+	cmp	x0, x1
+	adr	x1, abort_guest_exit_end
+	ccmp	x0, x1, #4, ne
+	b.ne	__hyp_panic
+	mov	x0, #(1 << ARM_EXIT_WITH_SERROR_BIT)
+	eret
+
 ENTRY(__hyp_do_panic)
 	mov	lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
 		      PSR_MODE_EL1h)
@@ -150,7 +172,6 @@ ENDPROC(\label)
 	invalid_vector	el2h_sync_invalid
 	invalid_vector	el2h_irq_invalid
 	invalid_vector	el2h_fiq_invalid
-	invalid_vector	el2h_error_invalid
 	invalid_vector	el1_sync_invalid
 	invalid_vector	el1_irq_invalid
 	invalid_vector	el1_fiq_invalid
@@ -168,7 +189,7 @@ ENTRY(__kvm_hyp_vector)
 	ventry	el2h_sync_invalid		// Synchronous EL2h
 	ventry	el2h_irq_invalid		// IRQ EL2h
 	ventry	el2h_fiq_invalid		// FIQ EL2h
-	ventry	el2h_error_invalid		// Error EL2h
+	ventry	el2_error			// Error EL2h
 
 	ventry	el1_sync			// Synchronous 64-bit EL1
 	ventry	el1_irq				// IRQ 64-bit EL1
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 5148b06..1233a55 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -292,6 +292,12 @@ again:
 	exit_code = __guest_enter(vcpu, host_ctxt);
 	/* And we're baaack! */
 
+	/*
+	 * We're using the raw exception code in order to only process
+	 * the trap if no SError is pending. We will come back to the
+	 * same PC once the SError has been injected, and replay the
+	 * trapping instruction.
+	 */
 	if (exit_code == ARM_EXCEPTION_TRAP && !__populate_fault_info(vcpu))
 		goto again;
 
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 09/19] arm64: KVM: Handle async aborts delivered while at EL2
@ 2016-09-06 13:02   ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: linux-arm-kernel

If EL1 generates an asynchronous abort and then traps into EL2
before the abort has been delivered, we may end-up with the
abort firing at the worse possible place: on the host.

In order to avoid this, it is necessary to take the abort at EL2,
by clearing the PSTATE.A bit. In order to survive this abort,
we do it at a point where we're in a known state with respect
to the world switch, and handle the resulting exception,
overloading the exit code in the process.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/kvm/hyp/entry.S     | 33 ++++++++++++++++++++++++++++++++-
 arch/arm64/kvm/hyp/hyp-entry.S | 25 +++++++++++++++++++++++--
 arch/arm64/kvm/hyp/switch.c    |  6 ++++++
 3 files changed, 61 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
index 3967c231..7662ef5 100644
--- a/arch/arm64/kvm/hyp/entry.S
+++ b/arch/arm64/kvm/hyp/entry.S
@@ -122,7 +122,38 @@ ENTRY(__guest_exit)
 	// Now restore the host regs
 	restore_callee_saved_regs x2
 
-	ret
+	// If we have a pending asynchronous abort, now is the
+	// time to find out. From your VAXorcist book, page 666:
+	// "Threaten me not, oh Evil one!  For I speak with
+	// the power of DEC, and I command thee to show thyself!"
+	mrs	x2, elr_el2
+	mrs	x3, esr_el2
+	mrs	x4, spsr_el2
+	mov	x5, x0
+
+	dsb	sy		// Synchronize against in-flight ld/st
+	msr	daifclr, #4	// Unmask aborts
+
+	// This is our single instruction exception window. A pending
+	// SError is guaranteed to occur at the earliest when we unmask
+	// it, and at the latest just after the ISB.
+	.global	abort_guest_exit_start
+abort_guest_exit_start:
+
+	isb
+
+	.global	abort_guest_exit_end
+abort_guest_exit_end:
+
+	// If the exception took place, restore the EL1 exception
+	// context so that we can report some information.
+	// Merge the exception code with the SError pending bit.
+	tbz	x0, #ARM_EXIT_WITH_SERROR_BIT, 1f
+	msr	elr_el2, x2
+	msr	esr_el2, x3
+	msr	spsr_el2, x4
+	orr	x0, x0, x5
+1:	ret
 ENDPROC(__guest_exit)
 
 ENTRY(__fpsimd_guest_restore)
diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
index d2f6640..4e92399 100644
--- a/arch/arm64/kvm/hyp/hyp-entry.S
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -126,6 +126,28 @@ el1_error:
 	mov	x0, #ARM_EXCEPTION_EL1_SERROR
 	b	__guest_exit
 
+el2_error:
+	/*
+	 * Only two possibilities:
+	 * 1) Either we come from the exit path, having just unmasked
+	 *    PSTATE.A: change the return code to an EL2 fault, and
+	 *    carry on, as we're already in a sane state to handle it.
+	 * 2) Or we come from anywhere else, and that's a bug: we panic.
+	 *
+	 * For (1), x0 contains the original return code and x1 doesn't
+	 * contain anything meaningful at that stage. We can reuse them
+	 * as temp registers.
+	 * For (2), who cares?
+	 */
+	mrs	x0, elr_el2
+	adr	x1, abort_guest_exit_start
+	cmp	x0, x1
+	adr	x1, abort_guest_exit_end
+	ccmp	x0, x1, #4, ne
+	b.ne	__hyp_panic
+	mov	x0, #(1 << ARM_EXIT_WITH_SERROR_BIT)
+	eret
+
 ENTRY(__hyp_do_panic)
 	mov	lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
 		      PSR_MODE_EL1h)
@@ -150,7 +172,6 @@ ENDPROC(\label)
 	invalid_vector	el2h_sync_invalid
 	invalid_vector	el2h_irq_invalid
 	invalid_vector	el2h_fiq_invalid
-	invalid_vector	el2h_error_invalid
 	invalid_vector	el1_sync_invalid
 	invalid_vector	el1_irq_invalid
 	invalid_vector	el1_fiq_invalid
@@ -168,7 +189,7 @@ ENTRY(__kvm_hyp_vector)
 	ventry	el2h_sync_invalid		// Synchronous EL2h
 	ventry	el2h_irq_invalid		// IRQ EL2h
 	ventry	el2h_fiq_invalid		// FIQ EL2h
-	ventry	el2h_error_invalid		// Error EL2h
+	ventry	el2_error			// Error EL2h
 
 	ventry	el1_sync			// Synchronous 64-bit EL1
 	ventry	el1_irq				// IRQ 64-bit EL1
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 5148b06..1233a55 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -292,6 +292,12 @@ again:
 	exit_code = __guest_enter(vcpu, host_ctxt);
 	/* And we're baaack! */
 
+	/*
+	 * We're using the raw exception code in order to only process
+	 * the trap if no SError is pending. We will come back to the
+	 * same PC once the SError has been injected, and replay the
+	 * trapping instruction.
+	 */
 	if (exit_code == ARM_EXCEPTION_TRAP && !__populate_fault_info(vcpu))
 		goto again;
 
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 10/19] arm: KVM: Preserve pending Virtual Abort in world switch
  2016-09-06 13:01 ` Marc Zyngier
@ 2016-09-06 13:02   ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: linux-arm-kernel, kvm, kvmarm

The HCR.VA bit is used to signal an Abort to a guest, and has
the peculiar feature of getting cleared when the guest has taken
the abort (this is the only bit that behaves as such in this register).

This means that if we signal such an abort, we must leave it in
the guest context until it disappears from HCR, and at which point
it must be cleared from the context.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/kvm/hyp/switch.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/kvm/hyp/switch.c b/arch/arm/kvm/hyp/switch.c
index b13caa9..8cda887 100644
--- a/arch/arm/kvm/hyp/switch.c
+++ b/arch/arm/kvm/hyp/switch.c
@@ -54,6 +54,15 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
 {
 	u32 val;
 
+	/*
+	 * If we pended a virtual abort, preserve it until it gets
+	 * cleared. See B1.9.9 (Virtual Abort exception) for details,
+	 * but the crucial bit is the zeroing of HCR.VA in the
+	 * pseudocode.
+	 */
+	if (vcpu->arch.hcr & HCR_VA)
+		vcpu->arch.hcr = read_sysreg(HCR);
+
 	write_sysreg(0, HCR);
 	write_sysreg(0, HSTR);
 	val = read_sysreg(HDCR);
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 10/19] arm: KVM: Preserve pending Virtual Abort in world switch
@ 2016-09-06 13:02   ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: linux-arm-kernel

The HCR.VA bit is used to signal an Abort to a guest, and has
the peculiar feature of getting cleared when the guest has taken
the abort (this is the only bit that behaves as such in this register).

This means that if we signal such an abort, we must leave it in
the guest context until it disappears from HCR, and at which point
it must be cleared from the context.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/kvm/hyp/switch.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/kvm/hyp/switch.c b/arch/arm/kvm/hyp/switch.c
index b13caa9..8cda887 100644
--- a/arch/arm/kvm/hyp/switch.c
+++ b/arch/arm/kvm/hyp/switch.c
@@ -54,6 +54,15 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
 {
 	u32 val;
 
+	/*
+	 * If we pended a virtual abort, preserve it until it gets
+	 * cleared. See B1.9.9 (Virtual Abort exception) for details,
+	 * but the crucial bit is the zeroing of HCR.VA in the
+	 * pseudocode.
+	 */
+	if (vcpu->arch.hcr & HCR_VA)
+		vcpu->arch.hcr = read_sysreg(HCR);
+
 	write_sysreg(0, HCR);
 	write_sysreg(0, HSTR);
 	val = read_sysreg(HDCR);
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 11/19] arm: KVM: Add Virtual Abort injection helper
  2016-09-06 13:01 ` Marc Zyngier
@ 2016-09-06 13:02   ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: linux-arm-kernel, kvm, kvmarm

Now that we're able to context switch the HCR.VA bit, let's
introduce a helper that injects an Abort into a vcpu.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/include/asm/kvm_emulate.h |  1 +
 arch/arm/kvm/emulate.c             | 12 ++++++++++++
 2 files changed, 13 insertions(+)

diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h
index 448d63c..9a8a45a 100644
--- a/arch/arm/include/asm/kvm_emulate.h
+++ b/arch/arm/include/asm/kvm_emulate.h
@@ -43,6 +43,7 @@ static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
 bool kvm_condition_valid32(const struct kvm_vcpu *vcpu);
 void kvm_skip_instr32(struct kvm_vcpu *vcpu, bool is_wide_instr);
 void kvm_inject_undefined(struct kvm_vcpu *vcpu);
+void kvm_inject_vabt(struct kvm_vcpu *vcpu);
 void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
 void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
 
diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
index ff9acd1..0064b86 100644
--- a/arch/arm/kvm/emulate.c
+++ b/arch/arm/kvm/emulate.c
@@ -303,3 +303,15 @@ void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
 {
 	inject_abt(vcpu, true, addr);
 }
+
+/**
+ * kvm_inject_vabt - inject an async abort / SError into the guest
+ * @vcpu: The VCPU to receive the exception
+ *
+ * It is assumed that this code is called from the VCPU thread and that the
+ * VCPU therefore is not currently executing guest code.
+ */
+void kvm_inject_vabt(struct kvm_vcpu *vcpu)
+{
+	vcpu_set_hcr(vcpu, vcpu_get_hcr(vcpu) | HCR_VA);
+}
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 11/19] arm: KVM: Add Virtual Abort injection helper
@ 2016-09-06 13:02   ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: linux-arm-kernel

Now that we're able to context switch the HCR.VA bit, let's
introduce a helper that injects an Abort into a vcpu.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/include/asm/kvm_emulate.h |  1 +
 arch/arm/kvm/emulate.c             | 12 ++++++++++++
 2 files changed, 13 insertions(+)

diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h
index 448d63c..9a8a45a 100644
--- a/arch/arm/include/asm/kvm_emulate.h
+++ b/arch/arm/include/asm/kvm_emulate.h
@@ -43,6 +43,7 @@ static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
 bool kvm_condition_valid32(const struct kvm_vcpu *vcpu);
 void kvm_skip_instr32(struct kvm_vcpu *vcpu, bool is_wide_instr);
 void kvm_inject_undefined(struct kvm_vcpu *vcpu);
+void kvm_inject_vabt(struct kvm_vcpu *vcpu);
 void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
 void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
 
diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
index ff9acd1..0064b86 100644
--- a/arch/arm/kvm/emulate.c
+++ b/arch/arm/kvm/emulate.c
@@ -303,3 +303,15 @@ void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
 {
 	inject_abt(vcpu, true, addr);
 }
+
+/**
+ * kvm_inject_vabt - inject an async abort / SError into the guest
+ * @vcpu: The VCPU to receive the exception
+ *
+ * It is assumed that this code is called from the VCPU thread and that the
+ * VCPU therefore is not currently executing guest code.
+ */
+void kvm_inject_vabt(struct kvm_vcpu *vcpu)
+{
+	vcpu_set_hcr(vcpu, vcpu_get_hcr(vcpu) | HCR_VA);
+}
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 12/19] arm: KVM: Add HYP async abort handler
  2016-09-06 13:01 ` Marc Zyngier
@ 2016-09-06 13:02   ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: linux-arm-kernel, kvm, kvmarm

If we've exited the guest because it has triggered an asynchronous
abort, a possible course of action is to let it know it screwed up
by giving it a Virtual Abort to chew on.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/kvm/handle_exit.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
index 3f1ef0d..863fdf4 100644
--- a/arch/arm/kvm/handle_exit.c
+++ b/arch/arm/kvm/handle_exit.c
@@ -160,6 +160,9 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
 		exit_handler = kvm_get_exit_handler(vcpu);
 
 		return exit_handler(vcpu, run);
+	case ARM_EXCEPTION_DATA_ABORT:
+		kvm_inject_vabt(vcpu);
+		return 1;
 	default:
 		kvm_pr_unimpl("Unsupported exception type: %d",
 			      exception_index);
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 12/19] arm: KVM: Add HYP async abort handler
@ 2016-09-06 13:02   ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: linux-arm-kernel

If we've exited the guest because it has triggered an asynchronous
abort, a possible course of action is to let it know it screwed up
by giving it a Virtual Abort to chew on.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/kvm/handle_exit.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
index 3f1ef0d..863fdf4 100644
--- a/arch/arm/kvm/handle_exit.c
+++ b/arch/arm/kvm/handle_exit.c
@@ -160,6 +160,9 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
 		exit_handler = kvm_get_exit_handler(vcpu);
 
 		return exit_handler(vcpu, run);
+	case ARM_EXCEPTION_DATA_ABORT:
+		kvm_inject_vabt(vcpu);
+		return 1;
 	default:
 		kvm_pr_unimpl("Unsupported exception type: %d",
 			      exception_index);
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 13/19] arm: KVM: Allow an exit code to be tagged with a Virtual Abort
  2016-09-06 13:01 ` Marc Zyngier
@ 2016-09-06 13:02   ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: linux-arm-kernel, kvm, kvmarm

An asynchronous abort can also be triggered whilst running at EL2.
But instead of making that a new error code, we need to communicate
it to the rest of KVM together with the exit reason.
So let's hijack a single bit that allows the exception code to be
tagged with a "pending Abort" information.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/include/asm/kvm_asm.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
index 58faff5..05e47fa 100644
--- a/arch/arm/include/asm/kvm_asm.h
+++ b/arch/arm/include/asm/kvm_asm.h
@@ -21,6 +21,10 @@
 
 #include <asm/virt.h>
 
+#define ARM_EXIT_WITH_ABORT_BIT  31
+#define ARM_EXCEPTION_CODE(x)	  ((x) & ~(1U << ARM_EXIT_WITH_ABORT_BIT))
+#define ARM_ABORT_PENDING(x)	  !!((x) & (1U << ARM_EXIT_WITH_ABORT_BIT))
+
 #define ARM_EXCEPTION_RESET	  0
 #define ARM_EXCEPTION_UNDEFINED   1
 #define ARM_EXCEPTION_SOFTWARE    2
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 13/19] arm: KVM: Allow an exit code to be tagged with a Virtual Abort
@ 2016-09-06 13:02   ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: linux-arm-kernel

An asynchronous abort can also be triggered whilst running at EL2.
But instead of making that a new error code, we need to communicate
it to the rest of KVM together with the exit reason.
So let's hijack a single bit that allows the exception code to be
tagged with a "pending Abort" information.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/include/asm/kvm_asm.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
index 58faff5..05e47fa 100644
--- a/arch/arm/include/asm/kvm_asm.h
+++ b/arch/arm/include/asm/kvm_asm.h
@@ -21,6 +21,10 @@
 
 #include <asm/virt.h>
 
+#define ARM_EXIT_WITH_ABORT_BIT  31
+#define ARM_EXCEPTION_CODE(x)	  ((x) & ~(1U << ARM_EXIT_WITH_ABORT_BIT))
+#define ARM_ABORT_PENDING(x)	  !!((x) & (1U << ARM_EXIT_WITH_ABORT_BIT))
+
 #define ARM_EXCEPTION_RESET	  0
 #define ARM_EXCEPTION_UNDEFINED   1
 #define ARM_EXCEPTION_SOFTWARE    2
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 14/19] arm: KVM: Handle async aborts delivered while at HYP
  2016-09-06 13:01 ` Marc Zyngier
@ 2016-09-06 13:02   ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: linux-arm-kernel, kvm, kvmarm

Just like for arm64, we can handle asynchronous aborts being
delivered at HYP while being caused by the guest. We use
the exact same method to catch such an abort, and soldier on.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/kvm/hyp/entry.S     | 31 +++++++++++++++++++++++++++++++
 arch/arm/kvm/hyp/hyp-entry.S | 16 +++++++++++++++-
 2 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/arch/arm/kvm/hyp/entry.S b/arch/arm/kvm/hyp/entry.S
index 21c2388..60783f3 100644
--- a/arch/arm/kvm/hyp/entry.S
+++ b/arch/arm/kvm/hyp/entry.S
@@ -18,6 +18,7 @@
 #include <linux/linkage.h>
 #include <asm/asm-offsets.h>
 #include <asm/kvm_arm.h>
+#include <asm/kvm_asm.h>
 
 	.arch_extension     virt
 
@@ -63,6 +64,36 @@ ENTRY(__guest_exit)
 	ldr	lr, [r0, #4]
 
 	mov	r0, r1
+	mrs	r1, SPSR
+	mrs	r2, ELR_hyp
+	mrc	p15, 4, r3, c5, c2, 0	@ HSR
+
+	/*
+	 * Force loads and stores to complete before unmasking aborts
+	 * and forcing the delivery of the exception. This gives us a
+	 * single instruction window, which the handler will try to
+	 * match.
+	 */
+	dsb	sy
+	cpsie	a
+
+	.global	abort_guest_exit_start
+abort_guest_exit_start:
+
+	isb
+
+	.global	abort_guest_exit_end
+abort_guest_exit_end:
+
+	/*
+	 * If we took an abort, r0[31] will be set, and cmp will set
+	 * the N bit in PSTATE.
+	 */
+	cmp	r0, #0
+	msrmi	SPSR_cxsf, r1
+	msrmi	ELR_hyp, r2
+	mcrmi	p15, 4, r3, c5, c2, 0	@ HSR
+
 	bx	lr
 ENDPROC(__guest_exit)
 
diff --git a/arch/arm/kvm/hyp/hyp-entry.S b/arch/arm/kvm/hyp/hyp-entry.S
index 7809138..96beb53 100644
--- a/arch/arm/kvm/hyp/hyp-entry.S
+++ b/arch/arm/kvm/hyp/hyp-entry.S
@@ -81,7 +81,6 @@ __kvm_hyp_vector:
 	invalid_vector	hyp_undef	ARM_EXCEPTION_UNDEFINED
 	invalid_vector	hyp_svc		ARM_EXCEPTION_SOFTWARE
 	invalid_vector	hyp_pabt	ARM_EXCEPTION_PREF_ABORT
-	invalid_vector	hyp_dabt	ARM_EXCEPTION_DATA_ABORT
 	invalid_vector	hyp_fiq		ARM_EXCEPTION_FIQ
 
 ENTRY(__hyp_do_panic)
@@ -164,6 +163,21 @@ hyp_irq:
 	load_vcpu r0			@ Load VCPU pointer to r0
 	b	__guest_exit
 
+hyp_dabt:
+	push	{r0, r1}
+	mrs	r0, ELR_hyp
+	ldr	r1, =abort_guest_exit_start
+THUMB(	add	r1, r1, #1)
+	cmp	r0, r1
+	ldrne	r1, =abort_guest_exit_end
+THUMB(	addne	r1, r1, #1)
+	cmpne	r0, r1
+	pop	{r0, r1}
+	bne	__hyp_panic
+
+	orr	r0, r0, #(1 << ARM_EXIT_WITH_ABORT_BIT)
+	eret
+
 	.ltorg
 
 	.popsection
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 14/19] arm: KVM: Handle async aborts delivered while at HYP
@ 2016-09-06 13:02   ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: linux-arm-kernel

Just like for arm64, we can handle asynchronous aborts being
delivered at HYP while being caused by the guest. We use
the exact same method to catch such an abort, and soldier on.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/kvm/hyp/entry.S     | 31 +++++++++++++++++++++++++++++++
 arch/arm/kvm/hyp/hyp-entry.S | 16 +++++++++++++++-
 2 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/arch/arm/kvm/hyp/entry.S b/arch/arm/kvm/hyp/entry.S
index 21c2388..60783f3 100644
--- a/arch/arm/kvm/hyp/entry.S
+++ b/arch/arm/kvm/hyp/entry.S
@@ -18,6 +18,7 @@
 #include <linux/linkage.h>
 #include <asm/asm-offsets.h>
 #include <asm/kvm_arm.h>
+#include <asm/kvm_asm.h>
 
 	.arch_extension     virt
 
@@ -63,6 +64,36 @@ ENTRY(__guest_exit)
 	ldr	lr, [r0, #4]
 
 	mov	r0, r1
+	mrs	r1, SPSR
+	mrs	r2, ELR_hyp
+	mrc	p15, 4, r3, c5, c2, 0	@ HSR
+
+	/*
+	 * Force loads and stores to complete before unmasking aborts
+	 * and forcing the delivery of the exception. This gives us a
+	 * single instruction window, which the handler will try to
+	 * match.
+	 */
+	dsb	sy
+	cpsie	a
+
+	.global	abort_guest_exit_start
+abort_guest_exit_start:
+
+	isb
+
+	.global	abort_guest_exit_end
+abort_guest_exit_end:
+
+	/*
+	 * If we took an abort, r0[31] will be set, and cmp will set
+	 * the N bit in PSTATE.
+	 */
+	cmp	r0, #0
+	msrmi	SPSR_cxsf, r1
+	msrmi	ELR_hyp, r2
+	mcrmi	p15, 4, r3, c5, c2, 0	@ HSR
+
 	bx	lr
 ENDPROC(__guest_exit)
 
diff --git a/arch/arm/kvm/hyp/hyp-entry.S b/arch/arm/kvm/hyp/hyp-entry.S
index 7809138..96beb53 100644
--- a/arch/arm/kvm/hyp/hyp-entry.S
+++ b/arch/arm/kvm/hyp/hyp-entry.S
@@ -81,7 +81,6 @@ __kvm_hyp_vector:
 	invalid_vector	hyp_undef	ARM_EXCEPTION_UNDEFINED
 	invalid_vector	hyp_svc		ARM_EXCEPTION_SOFTWARE
 	invalid_vector	hyp_pabt	ARM_EXCEPTION_PREF_ABORT
-	invalid_vector	hyp_dabt	ARM_EXCEPTION_DATA_ABORT
 	invalid_vector	hyp_fiq		ARM_EXCEPTION_FIQ
 
 ENTRY(__hyp_do_panic)
@@ -164,6 +163,21 @@ hyp_irq:
 	load_vcpu r0			@ Load VCPU pointer to r0
 	b	__guest_exit
 
+hyp_dabt:
+	push	{r0, r1}
+	mrs	r0, ELR_hyp
+	ldr	r1, =abort_guest_exit_start
+THUMB(	add	r1, r1, #1)
+	cmp	r0, r1
+	ldrne	r1, =abort_guest_exit_end
+THUMB(	addne	r1, r1, #1)
+	cmpne	r0, r1
+	pop	{r0, r1}
+	bne	__hyp_panic
+
+	orr	r0, r0, #(1 << ARM_EXIT_WITH_ABORT_BIT)
+	eret
+
 	.ltorg
 
 	.popsection
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 15/19] arm: KVM: Inject a Virtual Abort if it was pending
  2016-09-06 13:01 ` Marc Zyngier
@ 2016-09-06 13:02   ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: linux-arm-kernel, kvm, kvmarm

If we have caught an Abort whilst exiting, we've tagged the
exit code with the pending information. In that case, let's
re-inject the error into the guest, after having adjusted
the PC if required.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/kvm/handle_exit.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
index 863fdf4..4eacb5c 100644
--- a/arch/arm/kvm/handle_exit.c
+++ b/arch/arm/kvm/handle_exit.c
@@ -144,6 +144,25 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
 {
 	exit_handle_fn exit_handler;
 
+	if (ARM_ABORT_PENDING(exception_index)) {
+		u8 hsr_ec = kvm_vcpu_trap_get_class(vcpu);
+
+		/*
+		 * HVC/SMC already have an adjusted PC, which we need
+		 * to correct in order to return to after having
+		 * injected the abort.
+		 */
+		if (hsr_ec == HSR_EC_HVC || hsr_ec == HSR_EC_SMC) {
+			u32 adj =  kvm_vcpu_trap_il_is32bit(vcpu) ? 4 : 2;
+			*vcpu_pc(vcpu) -= adj;
+		}
+
+		kvm_inject_vabt(vcpu);
+		return 1;
+	}
+
+	exception_index = ARM_EXCEPTION_CODE(exception_index);
+
 	switch (exception_index) {
 	case ARM_EXCEPTION_IRQ:
 		return 1;
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 15/19] arm: KVM: Inject a Virtual Abort if it was pending
@ 2016-09-06 13:02   ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: linux-arm-kernel

If we have caught an Abort whilst exiting, we've tagged the
exit code with the pending information. In that case, let's
re-inject the error into the guest, after having adjusted
the PC if required.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/kvm/handle_exit.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
index 863fdf4..4eacb5c 100644
--- a/arch/arm/kvm/handle_exit.c
+++ b/arch/arm/kvm/handle_exit.c
@@ -144,6 +144,25 @@ int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
 {
 	exit_handle_fn exit_handler;
 
+	if (ARM_ABORT_PENDING(exception_index)) {
+		u8 hsr_ec = kvm_vcpu_trap_get_class(vcpu);
+
+		/*
+		 * HVC/SMC already have an adjusted PC, which we need
+		 * to correct in order to return to after having
+		 * injected the abort.
+		 */
+		if (hsr_ec == HSR_EC_HVC || hsr_ec == HSR_EC_SMC) {
+			u32 adj =  kvm_vcpu_trap_il_is32bit(vcpu) ? 4 : 2;
+			*vcpu_pc(vcpu) -= adj;
+		}
+
+		kvm_inject_vabt(vcpu);
+		return 1;
+	}
+
+	exception_index = ARM_EXCEPTION_CODE(exception_index);
+
 	switch (exception_index) {
 	case ARM_EXCEPTION_IRQ:
 		return 1;
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 16/19] arm: KVM: Drop unreachable HYP abort handlers
  2016-09-06 13:01 ` Marc Zyngier
@ 2016-09-06 13:02   ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: kvm, linux-arm-kernel, kvmarm

Both data and prefetch aborts occuring in HYP lead to a well
deserved panic. Let's get rid of these silly handlers.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/kvm/handle_exit.c | 27 ---------------------------
 1 file changed, 27 deletions(-)

diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
index 4eacb5c..4e40d19 100644
--- a/arch/arm/kvm/handle_exit.c
+++ b/arch/arm/kvm/handle_exit.c
@@ -28,14 +28,6 @@
 
 typedef int (*exit_handle_fn)(struct kvm_vcpu *, struct kvm_run *);
 
-static int handle_svc_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run)
-{
-	/* SVC called from Hyp mode should never get here */
-	kvm_debug("SVC called from Hyp mode shouldn't go here\n");
-	BUG();
-	return -EINVAL; /* Squash warning */
-}
-
 static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
 	int ret;
@@ -59,22 +51,6 @@ static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 	return 1;
 }
 
-static int handle_pabt_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run)
-{
-	/* The hypervisor should never cause aborts */
-	kvm_err("Prefetch Abort taken from Hyp mode at %#08lx (HSR: %#08x)\n",
-		kvm_vcpu_get_hfar(vcpu), kvm_vcpu_get_hsr(vcpu));
-	return -EFAULT;
-}
-
-static int handle_dabt_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run)
-{
-	/* This is either an error in the ws. code or an external abort */
-	kvm_err("Data Abort taken from Hyp mode at %#08lx (HSR: %#08x)\n",
-		kvm_vcpu_get_hfar(vcpu), kvm_vcpu_get_hsr(vcpu));
-	return -EFAULT;
-}
-
 /**
  * kvm_handle_wfx - handle a WFI or WFE instructions trapped in guests
  * @vcpu:	the vcpu pointer
@@ -112,13 +88,10 @@ static exit_handle_fn arm_exit_handlers[] = {
 	[HSR_EC_CP14_64]	= kvm_handle_cp14_access,
 	[HSR_EC_CP_0_13]	= kvm_handle_cp_0_13_access,
 	[HSR_EC_CP10_ID]	= kvm_handle_cp10_id,
-	[HSR_EC_SVC_HYP]	= handle_svc_hyp,
 	[HSR_EC_HVC]		= handle_hvc,
 	[HSR_EC_SMC]		= handle_smc,
 	[HSR_EC_IABT]		= kvm_handle_guest_abort,
-	[HSR_EC_IABT_HYP]	= handle_pabt_hyp,
 	[HSR_EC_DABT]		= kvm_handle_guest_abort,
-	[HSR_EC_DABT_HYP]	= handle_dabt_hyp,
 };
 
 static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu)
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 16/19] arm: KVM: Drop unreachable HYP abort handlers
@ 2016-09-06 13:02   ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: linux-arm-kernel

Both data and prefetch aborts occuring in HYP lead to a well
deserved panic. Let's get rid of these silly handlers.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/kvm/handle_exit.c | 27 ---------------------------
 1 file changed, 27 deletions(-)

diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
index 4eacb5c..4e40d19 100644
--- a/arch/arm/kvm/handle_exit.c
+++ b/arch/arm/kvm/handle_exit.c
@@ -28,14 +28,6 @@
 
 typedef int (*exit_handle_fn)(struct kvm_vcpu *, struct kvm_run *);
 
-static int handle_svc_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run)
-{
-	/* SVC called from Hyp mode should never get here */
-	kvm_debug("SVC called from Hyp mode shouldn't go here\n");
-	BUG();
-	return -EINVAL; /* Squash warning */
-}
-
 static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
 	int ret;
@@ -59,22 +51,6 @@ static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
 	return 1;
 }
 
-static int handle_pabt_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run)
-{
-	/* The hypervisor should never cause aborts */
-	kvm_err("Prefetch Abort taken from Hyp mode at %#08lx (HSR: %#08x)\n",
-		kvm_vcpu_get_hfar(vcpu), kvm_vcpu_get_hsr(vcpu));
-	return -EFAULT;
-}
-
-static int handle_dabt_hyp(struct kvm_vcpu *vcpu, struct kvm_run *run)
-{
-	/* This is either an error in the ws. code or an external abort */
-	kvm_err("Data Abort taken from Hyp mode at %#08lx (HSR: %#08x)\n",
-		kvm_vcpu_get_hfar(vcpu), kvm_vcpu_get_hsr(vcpu));
-	return -EFAULT;
-}
-
 /**
  * kvm_handle_wfx - handle a WFI or WFE instructions trapped in guests
  * @vcpu:	the vcpu pointer
@@ -112,13 +88,10 @@ static exit_handle_fn arm_exit_handlers[] = {
 	[HSR_EC_CP14_64]	= kvm_handle_cp14_access,
 	[HSR_EC_CP_0_13]	= kvm_handle_cp_0_13_access,
 	[HSR_EC_CP10_ID]	= kvm_handle_cp10_id,
-	[HSR_EC_SVC_HYP]	= handle_svc_hyp,
 	[HSR_EC_HVC]		= handle_hvc,
 	[HSR_EC_SMC]		= handle_smc,
 	[HSR_EC_IABT]		= kvm_handle_guest_abort,
-	[HSR_EC_IABT_HYP]	= handle_pabt_hyp,
 	[HSR_EC_DABT]		= kvm_handle_guest_abort,
-	[HSR_EC_DABT_HYP]	= handle_dabt_hyp,
 };
 
 static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu)
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 17/19] arm/arm64: KVM: Inject virtual abort when guest exits on external abort
  2016-09-06 13:01 ` Marc Zyngier
@ 2016-09-06 13:02   ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: linux-arm-kernel, kvm, kvmarm

If we spot a data abort bearing the ESR_EL2.EA bit set, we know that
this is an external abort, and that should be punished by a the injection
of an abort.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/kvm/mmu.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index bda27b6..6827b54 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -1434,6 +1434,11 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run)
 	int ret, idx;
 
 	is_iabt = kvm_vcpu_trap_is_iabt(vcpu);
+	if (unlikely(!is_iabt && kvm_vcpu_dabt_isextabt(vcpu))) {
+		kvm_inject_vabt(vcpu);
+		return 1;
+	}
+
 	fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
 
 	trace_kvm_guest_fault(*vcpu_pc(vcpu), kvm_vcpu_get_hsr(vcpu),
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 17/19] arm/arm64: KVM: Inject virtual abort when guest exits on external abort
@ 2016-09-06 13:02   ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: linux-arm-kernel

If we spot a data abort bearing the ESR_EL2.EA bit set, we know that
this is an external abort, and that should be punished by a the injection
of an abort.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/kvm/mmu.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index bda27b6..6827b54 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -1434,6 +1434,11 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run)
 	int ret, idx;
 
 	is_iabt = kvm_vcpu_trap_is_iabt(vcpu);
+	if (unlikely(!is_iabt && kvm_vcpu_dabt_isextabt(vcpu))) {
+		kvm_inject_vabt(vcpu);
+		return 1;
+	}
+
 	fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
 
 	trace_kvm_guest_fault(*vcpu_pc(vcpu), kvm_vcpu_get_hsr(vcpu),
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 18/19] arm/arm64: KVM: Remove external abort test from MMIO handling
  2016-09-06 13:01 ` Marc Zyngier
@ 2016-09-06 13:02   ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: linux-arm-kernel, kvm, kvmarm

As we know handle external aborts pretty early, we can get rid of
its handling in the MMIO code (which was a bit odd to begin with...).

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/kvm/mmio.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
index 10f80a6..b6e715f 100644
--- a/arch/arm/kvm/mmio.c
+++ b/arch/arm/kvm/mmio.c
@@ -126,12 +126,6 @@ static int decode_hsr(struct kvm_vcpu *vcpu, bool *is_write, int *len)
 	int access_size;
 	bool sign_extend;
 
-	if (kvm_vcpu_dabt_isextabt(vcpu)) {
-		/* cache operation on I/O addr, tell guest unsupported */
-		kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu));
-		return 1;
-	}
-
 	if (kvm_vcpu_dabt_iss1tw(vcpu)) {
 		/* page table accesses IO mem: tell guest to fix its TTBR */
 		kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu));
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 18/19] arm/arm64: KVM: Remove external abort test from MMIO handling
@ 2016-09-06 13:02   ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: linux-arm-kernel

As we know handle external aborts pretty early, we can get rid of
its handling in the MMIO code (which was a bit odd to begin with...).

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/kvm/mmio.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
index 10f80a6..b6e715f 100644
--- a/arch/arm/kvm/mmio.c
+++ b/arch/arm/kvm/mmio.c
@@ -126,12 +126,6 @@ static int decode_hsr(struct kvm_vcpu *vcpu, bool *is_write, int *len)
 	int access_size;
 	bool sign_extend;
 
-	if (kvm_vcpu_dabt_isextabt(vcpu)) {
-		/* cache operation on I/O addr, tell guest unsupported */
-		kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu));
-		return 1;
-	}
-
 	if (kvm_vcpu_dabt_iss1tw(vcpu)) {
 		/* page table accesses IO mem: tell guest to fix its TTBR */
 		kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu));
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 19/19] arm64: KVM: Inject a vSerror if detecting a bad GICV access at EL2
  2016-09-06 13:01 ` Marc Zyngier
@ 2016-09-06 13:02   ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: linux-arm-kernel, kvm, kvmarm

If, when proxying a GICV access at EL2, we detect that the guest is
doing something silly, report an EL1 SError instead ofgnoring the
access.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/kvm_hyp.h |  2 +-
 arch/arm64/kvm/hyp/switch.c      | 18 +++++++++++++++---
 virt/kvm/arm/hyp/vgic-v2-sr.c    | 21 ++++++++++++++++-----
 3 files changed, 32 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index 88ec3ac..b18e852 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -123,7 +123,7 @@ typeof(orig) * __hyp_text fname(void)					\
 
 void __vgic_v2_save_state(struct kvm_vcpu *vcpu);
 void __vgic_v2_restore_state(struct kvm_vcpu *vcpu);
-bool __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
+int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
 
 void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
 void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 1233a55..194184c 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -311,9 +311,21 @@ again:
 			!kvm_vcpu_dabt_isextabt(vcpu) &&
 			!kvm_vcpu_dabt_iss1tw(vcpu);
 
-		if (valid && __vgic_v2_perform_cpuif_access(vcpu)) {
-			__skip_instr(vcpu);
-			goto again;
+		if (valid) {
+			int ret = __vgic_v2_perform_cpuif_access(vcpu);
+
+			if (ret == 1) {
+				__skip_instr(vcpu);
+				goto again;
+			}
+
+			if (ret == -1) {
+				/* Promote an illegal access to an SError */
+				__skip_instr(vcpu);
+				exit_code = ARM_EXCEPTION_EL1_SERROR;
+			}
+
+			/* 0 falls through to be handler out of EL2 */
 		}
 	}
 
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index a052f20..c8aeb7b 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -170,7 +170,18 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
 }
 
 #ifdef CONFIG_ARM64
-bool __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
+/*
+ * __vgic_v2_perform_cpuif_access -- perform a GICV access on behalf of the
+ *				     guest.
+ *
+ * @vcpu: the offending vcpu
+ *
+ * Returns:
+ *  1: GICV access successfully performed
+ *  0: Not a GICV access
+ * -1: Illegal GICV access
+ */
+int __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = kern_hyp_va(vcpu->kvm);
 	struct vgic_dist *vgic = &kvm->arch.vgic;
@@ -185,15 +196,15 @@ bool __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
 	/* If not for GICV, move on */
 	if (fault_ipa <  vgic->vgic_cpu_base ||
 	    fault_ipa >= (vgic->vgic_cpu_base + KVM_VGIC_V2_CPU_SIZE))
-		return false;
+		return 0;
 
 	/* Reject anything but a 32bit access */
 	if (kvm_vcpu_dabt_get_as(vcpu) != sizeof(u32))
-		return false;
+		return -1;
 
 	/* Not aligned? Don't bother */
 	if (fault_ipa & 3)
-		return false;
+		return -1;
 
 	rd = kvm_vcpu_dabt_get_rd(vcpu);
 	addr  = kern_hyp_va((kern_hyp_va(&kvm_vgic_global_state))->vcpu_base_va);
@@ -210,6 +221,6 @@ bool __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
 							       sizeof(u32)));
 	}
 
-	return true;
+	return 1;
 }
 #endif
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 56+ messages in thread

* [PATCH 19/19] arm64: KVM: Inject a vSerror if detecting a bad GICV access at EL2
@ 2016-09-06 13:02   ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-06 13:02 UTC (permalink / raw)
  To: linux-arm-kernel

If, when proxying a GICV access at EL2, we detect that the guest is
doing something silly, report an EL1 SError instead ofgnoring the
access.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/kvm_hyp.h |  2 +-
 arch/arm64/kvm/hyp/switch.c      | 18 +++++++++++++++---
 virt/kvm/arm/hyp/vgic-v2-sr.c    | 21 ++++++++++++++++-----
 3 files changed, 32 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index 88ec3ac..b18e852 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -123,7 +123,7 @@ typeof(orig) * __hyp_text fname(void)					\
 
 void __vgic_v2_save_state(struct kvm_vcpu *vcpu);
 void __vgic_v2_restore_state(struct kvm_vcpu *vcpu);
-bool __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
+int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu);
 
 void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
 void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 1233a55..194184c 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -311,9 +311,21 @@ again:
 			!kvm_vcpu_dabt_isextabt(vcpu) &&
 			!kvm_vcpu_dabt_iss1tw(vcpu);
 
-		if (valid && __vgic_v2_perform_cpuif_access(vcpu)) {
-			__skip_instr(vcpu);
-			goto again;
+		if (valid) {
+			int ret = __vgic_v2_perform_cpuif_access(vcpu);
+
+			if (ret == 1) {
+				__skip_instr(vcpu);
+				goto again;
+			}
+
+			if (ret == -1) {
+				/* Promote an illegal access to an SError */
+				__skip_instr(vcpu);
+				exit_code = ARM_EXCEPTION_EL1_SERROR;
+			}
+
+			/* 0 falls through to be handler out of EL2 */
 		}
 	}
 
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index a052f20..c8aeb7b 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -170,7 +170,18 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
 }
 
 #ifdef CONFIG_ARM64
-bool __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
+/*
+ * __vgic_v2_perform_cpuif_access -- perform a GICV access on behalf of the
+ *				     guest.
+ *
+ * @vcpu: the offending vcpu
+ *
+ * Returns:
+ *  1: GICV access successfully performed
+ *  0: Not a GICV access
+ * -1: Illegal GICV access
+ */
+int __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = kern_hyp_va(vcpu->kvm);
 	struct vgic_dist *vgic = &kvm->arch.vgic;
@@ -185,15 +196,15 @@ bool __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
 	/* If not for GICV, move on */
 	if (fault_ipa <  vgic->vgic_cpu_base ||
 	    fault_ipa >= (vgic->vgic_cpu_base + KVM_VGIC_V2_CPU_SIZE))
-		return false;
+		return 0;
 
 	/* Reject anything but a 32bit access */
 	if (kvm_vcpu_dabt_get_as(vcpu) != sizeof(u32))
-		return false;
+		return -1;
 
 	/* Not aligned? Don't bother */
 	if (fault_ipa & 3)
-		return false;
+		return -1;
 
 	rd = kvm_vcpu_dabt_get_rd(vcpu);
 	addr  = kern_hyp_va((kern_hyp_va(&kvm_vgic_global_state))->vcpu_base_va);
@@ -210,6 +221,6 @@ bool __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
 							       sizeof(u32)));
 	}
 
-	return true;
+	return 1;
 }
 #endif
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 56+ messages in thread

* Re: [PATCH 09/19] arm64: KVM: Handle async aborts delivered while at EL2
  2016-09-06 13:02   ` Marc Zyngier
@ 2016-09-07 17:03     ` Christoffer Dall
  -1 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2016-09-07 17:03 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: kvm, linux-arm-kernel, kvmarm

On Tue, Sep 06, 2016 at 02:02:07PM +0100, Marc Zyngier wrote:
> If EL1 generates an asynchronous abort and then traps into EL2
> before the abort has been delivered, we may end-up with the
> abort firing at the worse possible place: on the host.
> 
> In order to avoid this, it is necessary to take the abort at EL2,
> by clearing the PSTATE.A bit. In order to survive this abort,
> we do it at a point where we're in a known state with respect
> to the world switch, and handle the resulting exception,
> overloading the exit code in the process.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  arch/arm64/kvm/hyp/entry.S     | 33 ++++++++++++++++++++++++++++++++-
>  arch/arm64/kvm/hyp/hyp-entry.S | 25 +++++++++++++++++++++++--
>  arch/arm64/kvm/hyp/switch.c    |  6 ++++++
>  3 files changed, 61 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
> index 3967c231..7662ef5 100644
> --- a/arch/arm64/kvm/hyp/entry.S
> +++ b/arch/arm64/kvm/hyp/entry.S
> @@ -122,7 +122,38 @@ ENTRY(__guest_exit)
>  	// Now restore the host regs
>  	restore_callee_saved_regs x2
>  
> -	ret
> +	// If we have a pending asynchronous abort, now is the
> +	// time to find out. From your VAXorcist book, page 666:
> +	// "Threaten me not, oh Evil one!  For I speak with
> +	// the power of DEC, and I command thee to show thyself!"
> +	mrs	x2, elr_el2
> +	mrs	x3, esr_el2
> +	mrs	x4, spsr_el2
> +	mov	x5, x0
> +
> +	dsb	sy		// Synchronize against in-flight ld/st
> +	msr	daifclr, #4	// Unmask aborts
> +
> +	// This is our single instruction exception window. A pending
> +	// SError is guaranteed to occur at the earliest when we unmask
> +	// it, and at the latest just after the ISB.

Why is it guaranteed to to occur at the latest after the ISB?  I thought
that asynchronous exceptions could in theory be deferred until forever,
but I am probably wrong about this.


Otherwise, this looks good!

-Christoffer

> +	.global	abort_guest_exit_start
> +abort_guest_exit_start:
> +
> +	isb
> +
> +	.global	abort_guest_exit_end
> +abort_guest_exit_end:
> +
> +	// If the exception took place, restore the EL1 exception
> +	// context so that we can report some information.
> +	// Merge the exception code with the SError pending bit.
> +	tbz	x0, #ARM_EXIT_WITH_SERROR_BIT, 1f
> +	msr	elr_el2, x2
> +	msr	esr_el2, x3
> +	msr	spsr_el2, x4
> +	orr	x0, x0, x5
> +1:	ret
>  ENDPROC(__guest_exit)
>  
>  ENTRY(__fpsimd_guest_restore)
> diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
> index d2f6640..4e92399 100644
> --- a/arch/arm64/kvm/hyp/hyp-entry.S
> +++ b/arch/arm64/kvm/hyp/hyp-entry.S
> @@ -126,6 +126,28 @@ el1_error:
>  	mov	x0, #ARM_EXCEPTION_EL1_SERROR
>  	b	__guest_exit
>  
> +el2_error:
> +	/*
> +	 * Only two possibilities:
> +	 * 1) Either we come from the exit path, having just unmasked
> +	 *    PSTATE.A: change the return code to an EL2 fault, and
> +	 *    carry on, as we're already in a sane state to handle it.
> +	 * 2) Or we come from anywhere else, and that's a bug: we panic.
> +	 *
> +	 * For (1), x0 contains the original return code and x1 doesn't
> +	 * contain anything meaningful at that stage. We can reuse them
> +	 * as temp registers.
> +	 * For (2), who cares?
> +	 */
> +	mrs	x0, elr_el2
> +	adr	x1, abort_guest_exit_start
> +	cmp	x0, x1
> +	adr	x1, abort_guest_exit_end
> +	ccmp	x0, x1, #4, ne
> +	b.ne	__hyp_panic
> +	mov	x0, #(1 << ARM_EXIT_WITH_SERROR_BIT)
> +	eret
> +
>  ENTRY(__hyp_do_panic)
>  	mov	lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
>  		      PSR_MODE_EL1h)
> @@ -150,7 +172,6 @@ ENDPROC(\label)
>  	invalid_vector	el2h_sync_invalid
>  	invalid_vector	el2h_irq_invalid
>  	invalid_vector	el2h_fiq_invalid
> -	invalid_vector	el2h_error_invalid
>  	invalid_vector	el1_sync_invalid
>  	invalid_vector	el1_irq_invalid
>  	invalid_vector	el1_fiq_invalid
> @@ -168,7 +189,7 @@ ENTRY(__kvm_hyp_vector)
>  	ventry	el2h_sync_invalid		// Synchronous EL2h
>  	ventry	el2h_irq_invalid		// IRQ EL2h
>  	ventry	el2h_fiq_invalid		// FIQ EL2h
> -	ventry	el2h_error_invalid		// Error EL2h
> +	ventry	el2_error			// Error EL2h
>  
>  	ventry	el1_sync			// Synchronous 64-bit EL1
>  	ventry	el1_irq				// IRQ 64-bit EL1
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 5148b06..1233a55 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -292,6 +292,12 @@ again:
>  	exit_code = __guest_enter(vcpu, host_ctxt);
>  	/* And we're baaack! */
>  
> +	/*
> +	 * We're using the raw exception code in order to only process
> +	 * the trap if no SError is pending. We will come back to the
> +	 * same PC once the SError has been injected, and replay the
> +	 * trapping instruction.
> +	 */
>  	if (exit_code == ARM_EXCEPTION_TRAP && !__populate_fault_info(vcpu))
>  		goto again;
>  
> -- 
> 2.1.4
> 

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 09/19] arm64: KVM: Handle async aborts delivered while at EL2
@ 2016-09-07 17:03     ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2016-09-07 17:03 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 06, 2016 at 02:02:07PM +0100, Marc Zyngier wrote:
> If EL1 generates an asynchronous abort and then traps into EL2
> before the abort has been delivered, we may end-up with the
> abort firing at the worse possible place: on the host.
> 
> In order to avoid this, it is necessary to take the abort at EL2,
> by clearing the PSTATE.A bit. In order to survive this abort,
> we do it at a point where we're in a known state with respect
> to the world switch, and handle the resulting exception,
> overloading the exit code in the process.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  arch/arm64/kvm/hyp/entry.S     | 33 ++++++++++++++++++++++++++++++++-
>  arch/arm64/kvm/hyp/hyp-entry.S | 25 +++++++++++++++++++++++--
>  arch/arm64/kvm/hyp/switch.c    |  6 ++++++
>  3 files changed, 61 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
> index 3967c231..7662ef5 100644
> --- a/arch/arm64/kvm/hyp/entry.S
> +++ b/arch/arm64/kvm/hyp/entry.S
> @@ -122,7 +122,38 @@ ENTRY(__guest_exit)
>  	// Now restore the host regs
>  	restore_callee_saved_regs x2
>  
> -	ret
> +	// If we have a pending asynchronous abort, now is the
> +	// time to find out. From your VAXorcist book, page 666:
> +	// "Threaten me not, oh Evil one!  For I speak with
> +	// the power of DEC, and I command thee to show thyself!"
> +	mrs	x2, elr_el2
> +	mrs	x3, esr_el2
> +	mrs	x4, spsr_el2
> +	mov	x5, x0
> +
> +	dsb	sy		// Synchronize against in-flight ld/st
> +	msr	daifclr, #4	// Unmask aborts
> +
> +	// This is our single instruction exception window. A pending
> +	// SError is guaranteed to occur at the earliest when we unmask
> +	// it, and at the latest just after the ISB.

Why is it guaranteed to to occur at the latest after the ISB?  I thought
that asynchronous exceptions could in theory be deferred until forever,
but I am probably wrong about this.


Otherwise, this looks good!

-Christoffer

> +	.global	abort_guest_exit_start
> +abort_guest_exit_start:
> +
> +	isb
> +
> +	.global	abort_guest_exit_end
> +abort_guest_exit_end:
> +
> +	// If the exception took place, restore the EL1 exception
> +	// context so that we can report some information.
> +	// Merge the exception code with the SError pending bit.
> +	tbz	x0, #ARM_EXIT_WITH_SERROR_BIT, 1f
> +	msr	elr_el2, x2
> +	msr	esr_el2, x3
> +	msr	spsr_el2, x4
> +	orr	x0, x0, x5
> +1:	ret
>  ENDPROC(__guest_exit)
>  
>  ENTRY(__fpsimd_guest_restore)
> diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
> index d2f6640..4e92399 100644
> --- a/arch/arm64/kvm/hyp/hyp-entry.S
> +++ b/arch/arm64/kvm/hyp/hyp-entry.S
> @@ -126,6 +126,28 @@ el1_error:
>  	mov	x0, #ARM_EXCEPTION_EL1_SERROR
>  	b	__guest_exit
>  
> +el2_error:
> +	/*
> +	 * Only two possibilities:
> +	 * 1) Either we come from the exit path, having just unmasked
> +	 *    PSTATE.A: change the return code to an EL2 fault, and
> +	 *    carry on, as we're already in a sane state to handle it.
> +	 * 2) Or we come from anywhere else, and that's a bug: we panic.
> +	 *
> +	 * For (1), x0 contains the original return code and x1 doesn't
> +	 * contain anything meaningful at that stage. We can reuse them
> +	 * as temp registers.
> +	 * For (2), who cares?
> +	 */
> +	mrs	x0, elr_el2
> +	adr	x1, abort_guest_exit_start
> +	cmp	x0, x1
> +	adr	x1, abort_guest_exit_end
> +	ccmp	x0, x1, #4, ne
> +	b.ne	__hyp_panic
> +	mov	x0, #(1 << ARM_EXIT_WITH_SERROR_BIT)
> +	eret
> +
>  ENTRY(__hyp_do_panic)
>  	mov	lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
>  		      PSR_MODE_EL1h)
> @@ -150,7 +172,6 @@ ENDPROC(\label)
>  	invalid_vector	el2h_sync_invalid
>  	invalid_vector	el2h_irq_invalid
>  	invalid_vector	el2h_fiq_invalid
> -	invalid_vector	el2h_error_invalid
>  	invalid_vector	el1_sync_invalid
>  	invalid_vector	el1_irq_invalid
>  	invalid_vector	el1_fiq_invalid
> @@ -168,7 +189,7 @@ ENTRY(__kvm_hyp_vector)
>  	ventry	el2h_sync_invalid		// Synchronous EL2h
>  	ventry	el2h_irq_invalid		// IRQ EL2h
>  	ventry	el2h_fiq_invalid		// FIQ EL2h
> -	ventry	el2h_error_invalid		// Error EL2h
> +	ventry	el2_error			// Error EL2h
>  
>  	ventry	el1_sync			// Synchronous 64-bit EL1
>  	ventry	el1_irq				// IRQ 64-bit EL1
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index 5148b06..1233a55 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -292,6 +292,12 @@ again:
>  	exit_code = __guest_enter(vcpu, host_ctxt);
>  	/* And we're baaack! */
>  
> +	/*
> +	 * We're using the raw exception code in order to only process
> +	 * the trap if no SError is pending. We will come back to the
> +	 * same PC once the SError has been injected, and replay the
> +	 * trapping instruction.
> +	 */
>  	if (exit_code == ARM_EXCEPTION_TRAP && !__populate_fault_info(vcpu))
>  		goto again;
>  
> -- 
> 2.1.4
> 

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 09/19] arm64: KVM: Handle async aborts delivered while at EL2
  2016-09-07 17:03     ` Christoffer Dall
@ 2016-09-07 17:21       ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-07 17:21 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: kvm, linux-arm-kernel, kvmarm

On 07/09/16 18:03, Christoffer Dall wrote:
> On Tue, Sep 06, 2016 at 02:02:07PM +0100, Marc Zyngier wrote:
>> If EL1 generates an asynchronous abort and then traps into EL2
>> before the abort has been delivered, we may end-up with the
>> abort firing at the worse possible place: on the host.
>>
>> In order to avoid this, it is necessary to take the abort at EL2,
>> by clearing the PSTATE.A bit. In order to survive this abort,
>> we do it at a point where we're in a known state with respect
>> to the world switch, and handle the resulting exception,
>> overloading the exit code in the process.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  arch/arm64/kvm/hyp/entry.S     | 33 ++++++++++++++++++++++++++++++++-
>>  arch/arm64/kvm/hyp/hyp-entry.S | 25 +++++++++++++++++++++++--
>>  arch/arm64/kvm/hyp/switch.c    |  6 ++++++
>>  3 files changed, 61 insertions(+), 3 deletions(-)
>>
>> diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
>> index 3967c231..7662ef5 100644
>> --- a/arch/arm64/kvm/hyp/entry.S
>> +++ b/arch/arm64/kvm/hyp/entry.S
>> @@ -122,7 +122,38 @@ ENTRY(__guest_exit)
>>  	// Now restore the host regs
>>  	restore_callee_saved_regs x2
>>  
>> -	ret
>> +	// If we have a pending asynchronous abort, now is the
>> +	// time to find out. From your VAXorcist book, page 666:
>> +	// "Threaten me not, oh Evil one!  For I speak with
>> +	// the power of DEC, and I command thee to show thyself!"
>> +	mrs	x2, elr_el2
>> +	mrs	x3, esr_el2
>> +	mrs	x4, spsr_el2
>> +	mov	x5, x0
>> +
>> +	dsb	sy		// Synchronize against in-flight ld/st
>> +	msr	daifclr, #4	// Unmask aborts
>> +
>> +	// This is our single instruction exception window. A pending
>> +	// SError is guaranteed to occur at the earliest when we unmask
>> +	// it, and at the latest just after the ISB.
> 
> Why is it guaranteed to to occur at the latest after the ISB?  I thought
> that asynchronous exceptions could in theory be deferred until forever,
> but I am probably wrong about this.

The DSB is going to force all transactions to be completed and at that
point, we shouldn't have anything being further delayed (this is not an
architectural guarantee, but something that happens to work on the cores
I have access to), and the potential exception becomes pending.

At this point, we perform the unmask. A pending exception *can* fire at
that point, but is not guaranteed to do so. But the ISB, being a
"context synchronization event", guarantees that the exception fires
before the first instruction that follows the ISB (see D1.14.4). This is
what gives us this one instruction window (after the unmask, or after
the isb).

Hope this helps,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 09/19] arm64: KVM: Handle async aborts delivered while at EL2
@ 2016-09-07 17:21       ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-07 17:21 UTC (permalink / raw)
  To: linux-arm-kernel

On 07/09/16 18:03, Christoffer Dall wrote:
> On Tue, Sep 06, 2016 at 02:02:07PM +0100, Marc Zyngier wrote:
>> If EL1 generates an asynchronous abort and then traps into EL2
>> before the abort has been delivered, we may end-up with the
>> abort firing at the worse possible place: on the host.
>>
>> In order to avoid this, it is necessary to take the abort at EL2,
>> by clearing the PSTATE.A bit. In order to survive this abort,
>> we do it at a point where we're in a known state with respect
>> to the world switch, and handle the resulting exception,
>> overloading the exit code in the process.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  arch/arm64/kvm/hyp/entry.S     | 33 ++++++++++++++++++++++++++++++++-
>>  arch/arm64/kvm/hyp/hyp-entry.S | 25 +++++++++++++++++++++++--
>>  arch/arm64/kvm/hyp/switch.c    |  6 ++++++
>>  3 files changed, 61 insertions(+), 3 deletions(-)
>>
>> diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
>> index 3967c231..7662ef5 100644
>> --- a/arch/arm64/kvm/hyp/entry.S
>> +++ b/arch/arm64/kvm/hyp/entry.S
>> @@ -122,7 +122,38 @@ ENTRY(__guest_exit)
>>  	// Now restore the host regs
>>  	restore_callee_saved_regs x2
>>  
>> -	ret
>> +	// If we have a pending asynchronous abort, now is the
>> +	// time to find out. From your VAXorcist book, page 666:
>> +	// "Threaten me not, oh Evil one!  For I speak with
>> +	// the power of DEC, and I command thee to show thyself!"
>> +	mrs	x2, elr_el2
>> +	mrs	x3, esr_el2
>> +	mrs	x4, spsr_el2
>> +	mov	x5, x0
>> +
>> +	dsb	sy		// Synchronize against in-flight ld/st
>> +	msr	daifclr, #4	// Unmask aborts
>> +
>> +	// This is our single instruction exception window. A pending
>> +	// SError is guaranteed to occur at the earliest when we unmask
>> +	// it, and at the latest just after the ISB.
> 
> Why is it guaranteed to to occur at the latest after the ISB?  I thought
> that asynchronous exceptions could in theory be deferred until forever,
> but I am probably wrong about this.

The DSB is going to force all transactions to be completed and at that
point, we shouldn't have anything being further delayed (this is not an
architectural guarantee, but something that happens to work on the cores
I have access to), and the potential exception becomes pending.

At this point, we perform the unmask. A pending exception *can* fire at
that point, but is not guaranteed to do so. But the ISB, being a
"context synchronization event", guarantees that the exception fires
before the first instruction that follows the ISB (see D1.14.4). This is
what gives us this one instruction window (after the unmask, or after
the isb).

Hope this helps,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 09/19] arm64: KVM: Handle async aborts delivered while at EL2
  2016-09-07 17:21       ` Marc Zyngier
@ 2016-09-08  8:47         ` Christoffer Dall
  -1 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2016-09-08  8:47 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: linux-arm-kernel, kvm, kvmarm

On Wed, Sep 07, 2016 at 06:21:55PM +0100, Marc Zyngier wrote:
> On 07/09/16 18:03, Christoffer Dall wrote:
> > On Tue, Sep 06, 2016 at 02:02:07PM +0100, Marc Zyngier wrote:
> >> If EL1 generates an asynchronous abort and then traps into EL2
> >> before the abort has been delivered, we may end-up with the
> >> abort firing at the worse possible place: on the host.
> >>
> >> In order to avoid this, it is necessary to take the abort at EL2,
> >> by clearing the PSTATE.A bit. In order to survive this abort,
> >> we do it at a point where we're in a known state with respect
> >> to the world switch, and handle the resulting exception,
> >> overloading the exit code in the process.
> >>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> ---
> >>  arch/arm64/kvm/hyp/entry.S     | 33 ++++++++++++++++++++++++++++++++-
> >>  arch/arm64/kvm/hyp/hyp-entry.S | 25 +++++++++++++++++++++++--
> >>  arch/arm64/kvm/hyp/switch.c    |  6 ++++++
> >>  3 files changed, 61 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
> >> index 3967c231..7662ef5 100644
> >> --- a/arch/arm64/kvm/hyp/entry.S
> >> +++ b/arch/arm64/kvm/hyp/entry.S
> >> @@ -122,7 +122,38 @@ ENTRY(__guest_exit)
> >>  	// Now restore the host regs
> >>  	restore_callee_saved_regs x2
> >>  
> >> -	ret
> >> +	// If we have a pending asynchronous abort, now is the
> >> +	// time to find out. From your VAXorcist book, page 666:
> >> +	// "Threaten me not, oh Evil one!  For I speak with
> >> +	// the power of DEC, and I command thee to show thyself!"
> >> +	mrs	x2, elr_el2
> >> +	mrs	x3, esr_el2
> >> +	mrs	x4, spsr_el2
> >> +	mov	x5, x0
> >> +
> >> +	dsb	sy		// Synchronize against in-flight ld/st
> >> +	msr	daifclr, #4	// Unmask aborts
> >> +
> >> +	// This is our single instruction exception window. A pending
> >> +	// SError is guaranteed to occur at the earliest when we unmask
> >> +	// it, and at the latest just after the ISB.
> > 
> > Why is it guaranteed to to occur at the latest after the ISB?  I thought
> > that asynchronous exceptions could in theory be deferred until forever,
> > but I am probably wrong about this.
> 
> The DSB is going to force all transactions to be completed and at that
> point, we shouldn't have anything being further delayed (this is not an
> architectural guarantee, but something that happens to work on the cores
> I have access to), and the potential exception becomes pending.
> 
> At this point, we perform the unmask. A pending exception *can* fire at
> that point, but is not guaranteed to do so. But the ISB, being a
> "context synchronization event", guarantees that the exception fires
> before the first instruction that follows the ISB (see D1.14.4). This is
> what gives us this one instruction window (after the unmask, or after
> the isb).
> 
Yes, this makes sense.  So if by whatever weird sequence of events we
see an SError after the ISB, we simply give up and admit that the system
is screwy, which also makes sense.

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 09/19] arm64: KVM: Handle async aborts delivered while at EL2
@ 2016-09-08  8:47         ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2016-09-08  8:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Sep 07, 2016 at 06:21:55PM +0100, Marc Zyngier wrote:
> On 07/09/16 18:03, Christoffer Dall wrote:
> > On Tue, Sep 06, 2016 at 02:02:07PM +0100, Marc Zyngier wrote:
> >> If EL1 generates an asynchronous abort and then traps into EL2
> >> before the abort has been delivered, we may end-up with the
> >> abort firing at the worse possible place: on the host.
> >>
> >> In order to avoid this, it is necessary to take the abort at EL2,
> >> by clearing the PSTATE.A bit. In order to survive this abort,
> >> we do it at a point where we're in a known state with respect
> >> to the world switch, and handle the resulting exception,
> >> overloading the exit code in the process.
> >>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> ---
> >>  arch/arm64/kvm/hyp/entry.S     | 33 ++++++++++++++++++++++++++++++++-
> >>  arch/arm64/kvm/hyp/hyp-entry.S | 25 +++++++++++++++++++++++--
> >>  arch/arm64/kvm/hyp/switch.c    |  6 ++++++
> >>  3 files changed, 61 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
> >> index 3967c231..7662ef5 100644
> >> --- a/arch/arm64/kvm/hyp/entry.S
> >> +++ b/arch/arm64/kvm/hyp/entry.S
> >> @@ -122,7 +122,38 @@ ENTRY(__guest_exit)
> >>  	// Now restore the host regs
> >>  	restore_callee_saved_regs x2
> >>  
> >> -	ret
> >> +	// If we have a pending asynchronous abort, now is the
> >> +	// time to find out. From your VAXorcist book, page 666:
> >> +	// "Threaten me not, oh Evil one!  For I speak with
> >> +	// the power of DEC, and I command thee to show thyself!"
> >> +	mrs	x2, elr_el2
> >> +	mrs	x3, esr_el2
> >> +	mrs	x4, spsr_el2
> >> +	mov	x5, x0
> >> +
> >> +	dsb	sy		// Synchronize against in-flight ld/st
> >> +	msr	daifclr, #4	// Unmask aborts
> >> +
> >> +	// This is our single instruction exception window. A pending
> >> +	// SError is guaranteed to occur at the earliest when we unmask
> >> +	// it, and at the latest just after the ISB.
> > 
> > Why is it guaranteed to to occur at the latest after the ISB?  I thought
> > that asynchronous exceptions could in theory be deferred until forever,
> > but I am probably wrong about this.
> 
> The DSB is going to force all transactions to be completed and at that
> point, we shouldn't have anything being further delayed (this is not an
> architectural guarantee, but something that happens to work on the cores
> I have access to), and the potential exception becomes pending.
> 
> At this point, we perform the unmask. A pending exception *can* fire at
> that point, but is not guaranteed to do so. But the ISB, being a
> "context synchronization event", guarantees that the exception fires
> before the first instruction that follows the ISB (see D1.14.4). This is
> what gives us this one instruction window (after the unmask, or after
> the isb).
> 
Yes, this makes sense.  So if by whatever weird sequence of events we
see an SError after the ISB, we simply give up and admit that the system
is screwy, which also makes sense.

Thanks,
-Christoffer

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 17/19] arm/arm64: KVM: Inject virtual abort when guest exits on external abort
  2016-09-06 13:02   ` Marc Zyngier
@ 2016-09-08  9:09     ` Christoffer Dall
  -1 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2016-09-08  9:09 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: kvm, linux-arm-kernel, kvmarm

On Tue, Sep 06, 2016 at 02:02:15PM +0100, Marc Zyngier wrote:
> If we spot a data abort bearing the ESR_EL2.EA bit set, we know that
> this is an external abort, and that should be punished by a the injection

nit: s/a//

(I can fix this up though)

> of an abort.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  arch/arm/kvm/mmu.c | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
> index bda27b6..6827b54 100644
> --- a/arch/arm/kvm/mmu.c
> +++ b/arch/arm/kvm/mmu.c
> @@ -1434,6 +1434,11 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  	int ret, idx;
>  
>  	is_iabt = kvm_vcpu_trap_is_iabt(vcpu);
> +	if (unlikely(!is_iabt && kvm_vcpu_dabt_isextabt(vcpu))) {
> +		kvm_inject_vabt(vcpu);
> +		return 1;
> +	}
> +
>  	fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
>  
>  	trace_kvm_guest_fault(*vcpu_pc(vcpu), kvm_vcpu_get_hsr(vcpu),
> -- 
> 2.1.4
> 

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 17/19] arm/arm64: KVM: Inject virtual abort when guest exits on external abort
@ 2016-09-08  9:09     ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2016-09-08  9:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 06, 2016 at 02:02:15PM +0100, Marc Zyngier wrote:
> If we spot a data abort bearing the ESR_EL2.EA bit set, we know that
> this is an external abort, and that should be punished by a the injection

nit: s/a//

(I can fix this up though)

> of an abort.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  arch/arm/kvm/mmu.c | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
> index bda27b6..6827b54 100644
> --- a/arch/arm/kvm/mmu.c
> +++ b/arch/arm/kvm/mmu.c
> @@ -1434,6 +1434,11 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  	int ret, idx;
>  
>  	is_iabt = kvm_vcpu_trap_is_iabt(vcpu);
> +	if (unlikely(!is_iabt && kvm_vcpu_dabt_isextabt(vcpu))) {
> +		kvm_inject_vabt(vcpu);
> +		return 1;
> +	}
> +
>  	fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
>  
>  	trace_kvm_guest_fault(*vcpu_pc(vcpu), kvm_vcpu_get_hsr(vcpu),
> -- 
> 2.1.4
> 

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 00/19] Handle guest-generated SErrors/Aborts
  2016-09-06 13:01 ` Marc Zyngier
@ 2016-09-08  9:44   ` Christoffer Dall
  -1 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2016-09-08  9:44 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: linux-arm-kernel, kvm, kvmarm

On Tue, Sep 06, 2016 at 02:01:58PM +0100, Marc Zyngier wrote:
> A little known "feature" of giving guest access to real memory mapped
> HW is that it could trigger asynchronous aborts (SError on ARMv8) if
> the guest accesses it in a non-conventional way (and depending on how
> HW and firmware have been integrated). So far, KVM lacks any support
> to handle this gracefully.
> 
> This series introduces a set of mechanisms to catch such a fault and
> deliver a vSError (or Virtual Abort for 32bit) to the offending vcpu.
> 
> These aborts can either trigger at EL1 (whilst the guest is running),
> or at EL2 (during the handling of an exit). The first case is pretty
> easy to handle (use the ad-hoc vectors on arm64, or decode the EA bit
> on arm), but the second one is a bit more fiddly, as we need to ensure
> that the exception is pending by the time we unmask it. This is
> achived by using some heavy DSBs on the hot path, with the following
> caveats:
> 
> - I've only been able to trigger the EL2 handling on A57 (Seatle,
>   Juno).
> - I've measured a 40/50 cycles hit on Juno (A57), but I haven't
>   measured the impact on bigger systems
> 
> The last patch of this series adds a missing feature to the
> GICV-proxying series, delivering a vSError to a guest that performed
> an illegal access to the GIC.
> 
> Patches on top of current kvmarm/queue + the GICV przying series.

przying?  proxying?  Or something in Polish perhaps?

For the series:
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

Applied, thanks.
-Christoffer

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 00/19] Handle guest-generated SErrors/Aborts
@ 2016-09-08  9:44   ` Christoffer Dall
  0 siblings, 0 replies; 56+ messages in thread
From: Christoffer Dall @ 2016-09-08  9:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 06, 2016 at 02:01:58PM +0100, Marc Zyngier wrote:
> A little known "feature" of giving guest access to real memory mapped
> HW is that it could trigger asynchronous aborts (SError on ARMv8) if
> the guest accesses it in a non-conventional way (and depending on how
> HW and firmware have been integrated). So far, KVM lacks any support
> to handle this gracefully.
> 
> This series introduces a set of mechanisms to catch such a fault and
> deliver a vSError (or Virtual Abort for 32bit) to the offending vcpu.
> 
> These aborts can either trigger at EL1 (whilst the guest is running),
> or at EL2 (during the handling of an exit). The first case is pretty
> easy to handle (use the ad-hoc vectors on arm64, or decode the EA bit
> on arm), but the second one is a bit more fiddly, as we need to ensure
> that the exception is pending by the time we unmask it. This is
> achived by using some heavy DSBs on the hot path, with the following
> caveats:
> 
> - I've only been able to trigger the EL2 handling on A57 (Seatle,
>   Juno).
> - I've measured a 40/50 cycles hit on Juno (A57), but I haven't
>   measured the impact on bigger systems
> 
> The last patch of this series adds a missing feature to the
> GICV-proxying series, delivering a vSError to a guest that performed
> an illegal access to the GIC.
> 
> Patches on top of current kvmarm/queue + the GICV przying series.

przying?  proxying?  Or something in Polish perhaps?

For the series:
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

Applied, thanks.
-Christoffer

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 00/19] Handle guest-generated SErrors/Aborts
  2016-09-06 13:01 ` Marc Zyngier
@ 2016-09-08  9:47   ` Wei Chen
  -1 siblings, 0 replies; 56+ messages in thread
From: Wei Chen @ 2016-09-08  9:47 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall
  Cc: kvm, linux-arm-kernel, kvmarm@lists.cs.columbia.edu; julien.grall

Hi Marc,

On 2016/9/6 21:09, Marc Zyngier wrote:
> A little known "feature" of giving guest access to real memory mapped
> HW is that it could trigger asynchronous aborts (SError on ARMv8) if
> the guest accesses it in a non-conventional way (and depending on how
> HW and firmware have been integrated). So far, KVM lacks any support
> to handle this gracefully.

I can reproduce this issue on Seattle board (ARM64), but I can't
reproduce it on FVP (Cortex-A15x2 ARM32). Did you mean that this issue
onlu takes place on ARMv8? Have you ever reproduced this issue on any
ARM32 platform?

Regards,

>
> This series introduces a set of mechanisms to catch such a fault and
> deliver a vSError (or Virtual Abort for 32bit) to the offending vcpu.
>
> These aborts can either trigger at EL1 (whilst the guest is running),
> or at EL2 (during the handling of an exit). The first case is pretty
> easy to handle (use the ad-hoc vectors on arm64, or decode the EA bit
> on arm), but the second one is a bit more fiddly, as we need to ensure
> that the exception is pending by the time we unmask it. This is
> achived by using some heavy DSBs on the hot path, with the following
> caveats:
>
> - I've only been able to trigger the EL2 handling on A57 (Seatle,
>   Juno).
> - I've measured a 40/50 cycles hit on Juno (A57), but I haven't
>   measured the impact on bigger systems
>
> The last patch of this series adds a missing feature to the
> GICV-proxying series, delivering a vSError to a guest that performed
> an illegal access to the GIC.
>
> Patches on top of current kvmarm/queue + the GICV przying series.
>
> Marc Zyngier (19):
>   arm64: KVM: Rename HCR_VA to HCR_VSE
>   arm64: KVM: Preserve pending vSError in world switch
>   arm64: KVM: Add Virtual Abort injection helper
>   arm64: KVM: Add exception code to report EL1 asynchronous aborts
>   arm64: KVM: Add EL1 async abort handler
>   arm64: KVM: Route asynchronous aborts
>   arm64: KVM: Allow an exit code to be tagged with an SError
>   arm64: KVM: Inject a Virtual SError if it was pending
>   arm64: KVM: Handle async aborts delivered while at EL2
>   arm: KVM: Preserve pending Virtual Abort in world switch
>   arm: KVM: Add Virtual Abort injection helper
>   arm: KVM: Add HYP async abort handler
>   arm: KVM: Allow an exit code to be tagged with a Virtual Abort
>   arm: KVM: Handle async aborts delivered while at HYP
>   arm: KVM: Inject a Virtual Abort if it was pending
>   arm: KVM: Drop unreachable HYP abort handlers
>   arm/arm64: KVM: Inject virtual abort when guest exits on external
>     abort
>   arm/arm64: KVM: Remove external abort test from MMIO handling
>   arm64: KVM: Inject a vSerror if detecting a bad GICV access at EL2
>
>  arch/arm/include/asm/kvm_asm.h       |  4 +++
>  arch/arm/include/asm/kvm_emulate.h   |  1 +
>  arch/arm/kvm/emulate.c               | 12 +++++++++
>  arch/arm/kvm/handle_exit.c           | 49 ++++++++++++++++--------------------
>  arch/arm/kvm/hyp/entry.S             | 31 +++++++++++++++++++++++
>  arch/arm/kvm/hyp/hyp-entry.S         | 16 +++++++++++-
>  arch/arm/kvm/hyp/switch.c            |  9 +++++++
>  arch/arm/kvm/mmio.c                  |  6 -----
>  arch/arm/kvm/mmu.c                   |  5 ++++
>  arch/arm64/include/asm/kvm_arm.h     |  4 +--
>  arch/arm64/include/asm/kvm_asm.h     |  9 +++++--
>  arch/arm64/include/asm/kvm_emulate.h |  1 +
>  arch/arm64/include/asm/kvm_hyp.h     |  2 +-
>  arch/arm64/kvm/handle_exit.c         | 23 +++++++++++++++++
>  arch/arm64/kvm/hyp/entry.S           | 33 +++++++++++++++++++++++-
>  arch/arm64/kvm/hyp/hyp-entry.S       | 36 ++++++++++++++++++++++----
>  arch/arm64/kvm/hyp/switch.c          | 33 +++++++++++++++++++++---
>  arch/arm64/kvm/inject_fault.c        | 12 +++++++++
>  virt/kvm/arm/hyp/vgic-v2-sr.c        | 21 ++++++++++++----
>  19 files changed, 254 insertions(+), 53 deletions(-)
>


--
Regards,
Wei Chen
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 00/19] Handle guest-generated SErrors/Aborts
@ 2016-09-08  9:47   ` Wei Chen
  0 siblings, 0 replies; 56+ messages in thread
From: Wei Chen @ 2016-09-08  9:47 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Marc,

On 2016/9/6 21:09, Marc Zyngier wrote:
> A little known "feature" of giving guest access to real memory mapped
> HW is that it could trigger asynchronous aborts (SError on ARMv8) if
> the guest accesses it in a non-conventional way (and depending on how
> HW and firmware have been integrated). So far, KVM lacks any support
> to handle this gracefully.

I can reproduce this issue on Seattle board (ARM64), but I can't
reproduce it on FVP (Cortex-A15x2 ARM32). Did you mean that this issue
onlu takes place on ARMv8? Have you ever reproduced this issue on any
ARM32 platform?

Regards,

>
> This series introduces a set of mechanisms to catch such a fault and
> deliver a vSError (or Virtual Abort for 32bit) to the offending vcpu.
>
> These aborts can either trigger at EL1 (whilst the guest is running),
> or at EL2 (during the handling of an exit). The first case is pretty
> easy to handle (use the ad-hoc vectors on arm64, or decode the EA bit
> on arm), but the second one is a bit more fiddly, as we need to ensure
> that the exception is pending by the time we unmask it. This is
> achived by using some heavy DSBs on the hot path, with the following
> caveats:
>
> - I've only been able to trigger the EL2 handling on A57 (Seatle,
>   Juno).
> - I've measured a 40/50 cycles hit on Juno (A57), but I haven't
>   measured the impact on bigger systems
>
> The last patch of this series adds a missing feature to the
> GICV-proxying series, delivering a vSError to a guest that performed
> an illegal access to the GIC.
>
> Patches on top of current kvmarm/queue + the GICV przying series.
>
> Marc Zyngier (19):
>   arm64: KVM: Rename HCR_VA to HCR_VSE
>   arm64: KVM: Preserve pending vSError in world switch
>   arm64: KVM: Add Virtual Abort injection helper
>   arm64: KVM: Add exception code to report EL1 asynchronous aborts
>   arm64: KVM: Add EL1 async abort handler
>   arm64: KVM: Route asynchronous aborts
>   arm64: KVM: Allow an exit code to be tagged with an SError
>   arm64: KVM: Inject a Virtual SError if it was pending
>   arm64: KVM: Handle async aborts delivered while at EL2
>   arm: KVM: Preserve pending Virtual Abort in world switch
>   arm: KVM: Add Virtual Abort injection helper
>   arm: KVM: Add HYP async abort handler
>   arm: KVM: Allow an exit code to be tagged with a Virtual Abort
>   arm: KVM: Handle async aborts delivered while at HYP
>   arm: KVM: Inject a Virtual Abort if it was pending
>   arm: KVM: Drop unreachable HYP abort handlers
>   arm/arm64: KVM: Inject virtual abort when guest exits on external
>     abort
>   arm/arm64: KVM: Remove external abort test from MMIO handling
>   arm64: KVM: Inject a vSerror if detecting a bad GICV access at EL2
>
>  arch/arm/include/asm/kvm_asm.h       |  4 +++
>  arch/arm/include/asm/kvm_emulate.h   |  1 +
>  arch/arm/kvm/emulate.c               | 12 +++++++++
>  arch/arm/kvm/handle_exit.c           | 49 ++++++++++++++++--------------------
>  arch/arm/kvm/hyp/entry.S             | 31 +++++++++++++++++++++++
>  arch/arm/kvm/hyp/hyp-entry.S         | 16 +++++++++++-
>  arch/arm/kvm/hyp/switch.c            |  9 +++++++
>  arch/arm/kvm/mmio.c                  |  6 -----
>  arch/arm/kvm/mmu.c                   |  5 ++++
>  arch/arm64/include/asm/kvm_arm.h     |  4 +--
>  arch/arm64/include/asm/kvm_asm.h     |  9 +++++--
>  arch/arm64/include/asm/kvm_emulate.h |  1 +
>  arch/arm64/include/asm/kvm_hyp.h     |  2 +-
>  arch/arm64/kvm/handle_exit.c         | 23 +++++++++++++++++
>  arch/arm64/kvm/hyp/entry.S           | 33 +++++++++++++++++++++++-
>  arch/arm64/kvm/hyp/hyp-entry.S       | 36 ++++++++++++++++++++++----
>  arch/arm64/kvm/hyp/switch.c          | 33 +++++++++++++++++++++---
>  arch/arm64/kvm/inject_fault.c        | 12 +++++++++
>  virt/kvm/arm/hyp/vgic-v2-sr.c        | 21 ++++++++++++----
>  19 files changed, 254 insertions(+), 53 deletions(-)
>


--
Regards,
Wei Chen
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 00/19] Handle guest-generated SErrors/Aborts
  2016-09-08  9:44   ` Christoffer Dall
@ 2016-09-08  9:55     ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-08  9:55 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: linux-arm-kernel, kvm, kvmarm

On 08/09/16 10:44, Christoffer Dall wrote:
> On Tue, Sep 06, 2016 at 02:01:58PM +0100, Marc Zyngier wrote:
>> A little known "feature" of giving guest access to real memory mapped
>> HW is that it could trigger asynchronous aborts (SError on ARMv8) if
>> the guest accesses it in a non-conventional way (and depending on how
>> HW and firmware have been integrated). So far, KVM lacks any support
>> to handle this gracefully.
>>
>> This series introduces a set of mechanisms to catch such a fault and
>> deliver a vSError (or Virtual Abort for 32bit) to the offending vcpu.
>>
>> These aborts can either trigger at EL1 (whilst the guest is running),
>> or at EL2 (during the handling of an exit). The first case is pretty
>> easy to handle (use the ad-hoc vectors on arm64, or decode the EA bit
>> on arm), but the second one is a bit more fiddly, as we need to ensure
>> that the exception is pending by the time we unmask it. This is
>> achived by using some heavy DSBs on the hot path, with the following
>> caveats:
>>
>> - I've only been able to trigger the EL2 handling on A57 (Seatle,
>>   Juno).
>> - I've measured a 40/50 cycles hit on Juno (A57), but I haven't
>>   measured the impact on bigger systems
>>
>> The last patch of this series adds a missing feature to the
>> GICV-proxying series, delivering a vSError to a guest that performed
>> an illegal access to the GIC.
>>
>> Patches on top of current kvmarm/queue + the GICV przying series.
> 
> przying?  proxying?  Or something in Polish perhaps?

Proxying, with added fat fingers... ;-)

> 
> For the series:
> Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

Thanks!

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 00/19] Handle guest-generated SErrors/Aborts
@ 2016-09-08  9:55     ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-08  9:55 UTC (permalink / raw)
  To: linux-arm-kernel

On 08/09/16 10:44, Christoffer Dall wrote:
> On Tue, Sep 06, 2016 at 02:01:58PM +0100, Marc Zyngier wrote:
>> A little known "feature" of giving guest access to real memory mapped
>> HW is that it could trigger asynchronous aborts (SError on ARMv8) if
>> the guest accesses it in a non-conventional way (and depending on how
>> HW and firmware have been integrated). So far, KVM lacks any support
>> to handle this gracefully.
>>
>> This series introduces a set of mechanisms to catch such a fault and
>> deliver a vSError (or Virtual Abort for 32bit) to the offending vcpu.
>>
>> These aborts can either trigger at EL1 (whilst the guest is running),
>> or at EL2 (during the handling of an exit). The first case is pretty
>> easy to handle (use the ad-hoc vectors on arm64, or decode the EA bit
>> on arm), but the second one is a bit more fiddly, as we need to ensure
>> that the exception is pending by the time we unmask it. This is
>> achived by using some heavy DSBs on the hot path, with the following
>> caveats:
>>
>> - I've only been able to trigger the EL2 handling on A57 (Seatle,
>>   Juno).
>> - I've measured a 40/50 cycles hit on Juno (A57), but I haven't
>>   measured the impact on bigger systems
>>
>> The last patch of this series adds a missing feature to the
>> GICV-proxying series, delivering a vSError to a guest that performed
>> an illegal access to the GIC.
>>
>> Patches on top of current kvmarm/queue + the GICV przying series.
> 
> przying?  proxying?  Or something in Polish perhaps?

Proxying, with added fat fingers... ;-)

> 
> For the series:
> Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

Thanks!

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 00/19] Handle guest-generated SErrors/Aborts
  2016-09-08  9:47   ` Wei Chen
@ 2016-09-08 10:02     ` Marc Zyngier
  -1 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-08 10:02 UTC (permalink / raw)
  To: Wei Chen, Christoffer Dall
  Cc: kvm, linux-arm-kernel, kvmarm@lists.cs.columbia.edu; julien.grall

Hi Wei,

On 08/09/16 10:47, Wei Chen wrote:
> Hi Marc,
> 
> On 2016/9/6 21:09, Marc Zyngier wrote:
>> A little known "feature" of giving guest access to real memory mapped
>> HW is that it could trigger asynchronous aborts (SError on ARMv8) if
>> the guest accesses it in a non-conventional way (and depending on how
>> HW and firmware have been integrated). So far, KVM lacks any support
>> to handle this gracefully.
> 
> I can reproduce this issue on Seattle board (ARM64), but I can't
> reproduce it on FVP (Cortex-A15x2 ARM32). Did you mean that this issue 
> onlu takes place on ARMv8? Have you ever reproduced this issue on any 
> ARM32 platform?

On a 32bit platform, I've only managed to get an external abort firing
while running at EL1 and then taken to HYP. But that doesn't mean that
32bit systems are immune to this. It completely depends on the system
integration (how fast the error generating peripheral replies and how
the error is exposed to the CPU, for example).

As for the model, I'd be surprised if it had any facility for this. Most
of that is IMPDEF, and ignoring the error seems to be a valid
implementation...

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 00/19] Handle guest-generated SErrors/Aborts
@ 2016-09-08 10:02     ` Marc Zyngier
  0 siblings, 0 replies; 56+ messages in thread
From: Marc Zyngier @ 2016-09-08 10:02 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Wei,

On 08/09/16 10:47, Wei Chen wrote:
> Hi Marc,
> 
> On 2016/9/6 21:09, Marc Zyngier wrote:
>> A little known "feature" of giving guest access to real memory mapped
>> HW is that it could trigger asynchronous aborts (SError on ARMv8) if
>> the guest accesses it in a non-conventional way (and depending on how
>> HW and firmware have been integrated). So far, KVM lacks any support
>> to handle this gracefully.
> 
> I can reproduce this issue on Seattle board (ARM64), but I can't
> reproduce it on FVP (Cortex-A15x2 ARM32). Did you mean that this issue 
> onlu takes place on ARMv8? Have you ever reproduced this issue on any 
> ARM32 platform?

On a 32bit platform, I've only managed to get an external abort firing
while running at EL1 and then taken to HYP. But that doesn't mean that
32bit systems are immune to this. It completely depends on the system
integration (how fast the error generating peripheral replies and how
the error is exposed to the CPU, for example).

As for the model, I'd be surprised if it had any facility for this. Most
of that is IMPDEF, and ignoring the error seems to be a valid
implementation...

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 56+ messages in thread

end of thread, other threads:[~2016-09-08 10:02 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-06 13:01 [PATCH 00/19] Handle guest-generated SErrors/Aborts Marc Zyngier
2016-09-06 13:01 ` Marc Zyngier
2016-09-06 13:01 ` [PATCH 01/19] arm64: KVM: Rename HCR_VA to HCR_VSE Marc Zyngier
2016-09-06 13:01   ` Marc Zyngier
2016-09-06 13:02 ` [PATCH 02/19] arm64: KVM: Preserve pending vSError in world switch Marc Zyngier
2016-09-06 13:02   ` Marc Zyngier
2016-09-06 13:02 ` [PATCH 03/19] arm64: KVM: Add Virtual Abort injection helper Marc Zyngier
2016-09-06 13:02   ` Marc Zyngier
2016-09-06 13:02 ` [PATCH 04/19] arm64: KVM: Add exception code to report EL1 asynchronous aborts Marc Zyngier
2016-09-06 13:02   ` Marc Zyngier
2016-09-06 13:02 ` [PATCH 05/19] arm64: KVM: Add EL1 async abort handler Marc Zyngier
2016-09-06 13:02   ` Marc Zyngier
2016-09-06 13:02 ` [PATCH 06/19] arm64: KVM: Route asynchronous aborts Marc Zyngier
2016-09-06 13:02   ` Marc Zyngier
2016-09-06 13:02 ` [PATCH 07/19] arm64: KVM: Allow an exit code to be tagged with an SError Marc Zyngier
2016-09-06 13:02   ` Marc Zyngier
2016-09-06 13:02 ` [PATCH 08/19] arm64: KVM: Inject a Virtual SError if it was pending Marc Zyngier
2016-09-06 13:02   ` Marc Zyngier
2016-09-06 13:02 ` [PATCH 09/19] arm64: KVM: Handle async aborts delivered while at EL2 Marc Zyngier
2016-09-06 13:02   ` Marc Zyngier
2016-09-07 17:03   ` Christoffer Dall
2016-09-07 17:03     ` Christoffer Dall
2016-09-07 17:21     ` Marc Zyngier
2016-09-07 17:21       ` Marc Zyngier
2016-09-08  8:47       ` Christoffer Dall
2016-09-08  8:47         ` Christoffer Dall
2016-09-06 13:02 ` [PATCH 10/19] arm: KVM: Preserve pending Virtual Abort in world switch Marc Zyngier
2016-09-06 13:02   ` Marc Zyngier
2016-09-06 13:02 ` [PATCH 11/19] arm: KVM: Add Virtual Abort injection helper Marc Zyngier
2016-09-06 13:02   ` Marc Zyngier
2016-09-06 13:02 ` [PATCH 12/19] arm: KVM: Add HYP async abort handler Marc Zyngier
2016-09-06 13:02   ` Marc Zyngier
2016-09-06 13:02 ` [PATCH 13/19] arm: KVM: Allow an exit code to be tagged with a Virtual Abort Marc Zyngier
2016-09-06 13:02   ` Marc Zyngier
2016-09-06 13:02 ` [PATCH 14/19] arm: KVM: Handle async aborts delivered while at HYP Marc Zyngier
2016-09-06 13:02   ` Marc Zyngier
2016-09-06 13:02 ` [PATCH 15/19] arm: KVM: Inject a Virtual Abort if it was pending Marc Zyngier
2016-09-06 13:02   ` Marc Zyngier
2016-09-06 13:02 ` [PATCH 16/19] arm: KVM: Drop unreachable HYP abort handlers Marc Zyngier
2016-09-06 13:02   ` Marc Zyngier
2016-09-06 13:02 ` [PATCH 17/19] arm/arm64: KVM: Inject virtual abort when guest exits on external abort Marc Zyngier
2016-09-06 13:02   ` Marc Zyngier
2016-09-08  9:09   ` Christoffer Dall
2016-09-08  9:09     ` Christoffer Dall
2016-09-06 13:02 ` [PATCH 18/19] arm/arm64: KVM: Remove external abort test from MMIO handling Marc Zyngier
2016-09-06 13:02   ` Marc Zyngier
2016-09-06 13:02 ` [PATCH 19/19] arm64: KVM: Inject a vSerror if detecting a bad GICV access at EL2 Marc Zyngier
2016-09-06 13:02   ` Marc Zyngier
2016-09-08  9:44 ` [PATCH 00/19] Handle guest-generated SErrors/Aborts Christoffer Dall
2016-09-08  9:44   ` Christoffer Dall
2016-09-08  9:55   ` Marc Zyngier
2016-09-08  9:55     ` Marc Zyngier
2016-09-08  9:47 ` Wei Chen
2016-09-08  9:47   ` Wei Chen
2016-09-08 10:02   ` Marc Zyngier
2016-09-08 10:02     ` Marc Zyngier

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.