All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/25] arm64: KVM: Mediate access to GICv3 sysregs at EL2
@ 2017-06-01 10:20 ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:20 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: David Daney, Catalin Marinas, Mark Rutland, Robert Richter,
	Eric Auger, kvmarm, linux-arm-kernel, kvm

Some systems have less than perfect GICv3 implementations, leading to
all kind of ugly issues (guest hanging, host dying). In order to allow
some level of diagnostic, and in some cases implement workarounds,
this series enables the trapping of both Group-0, Group-1 and Common
sysregs. Mediating the access at EL2 allows some form of sanity
checking that the HW is sometimes sorely lacking.

Instead of fully emulating a GICv3 CPU interface, we still use the
existing HW (list registers, AP registers, VMCR...), which allows the
code to be independent from the rest of the KVM code, and to cope with
partial trapping.

Of course, trapping has a cost, which is why this must be either
enabled on the command line, or selected by another cpu capability
(see Cavium erratum 30115). A quick test on an A57-based platform
shows a 25% hit when repeatedly banging on the trapped registers,
while normal workloads do not seem to suffer noticeably from such
trapping (hackbench variance is in the usual noise, despite being very
IPI happy).

This has been tested on a dual socket Thundex-X and a Freescale LS-2085a.

I've taken the liberty to rebase David Daney's initial Cavium erratum
30115 workaround on top of this series, and included it here as a
typical use case.

- From v1:
  * Fix bug in DIR handling which would have performed a deactivation even
    when EOImode==0
  * Some minor cleanups and clarifications.
  * All the initial fixes have already been merged.
  * Rebased on 4.12-rc3.

David Daney (2):
  arm64: Add MIDR values for Cavium cn83XX SoCs
  arm64: Add workaround for Cavium Thunder erratum 30115

Marc Zyngier (23):
  arm64: Add a facility to turn an ESR syndrome into a sysreg encoding
  KVM: arm/arm64: vgic-v3: Add accessors for the ICH_APxRn_EL2 registers
  KVM: arm64: Make kvm_condition_valid32() accessible from EL2
  KVM: arm64: vgic-v3: Add hook to handle guest GICv3 sysreg accesses at
    EL2
  KVM: arm64: vgic-v3: Add ICV_BPR1_EL1 handler
  KVM: arm64: vgic-v3: Add ICV_IGRPEN1_EL1 handler
  KVM: arm64: vgic-v3: Add ICV_IAR1_EL1 handler
  KVM: arm64: vgic-v3: Add ICV_EOIR1_EL1 handler
  KVM: arm64: vgic-v3: Add ICV_AP1Rn_EL1 handler
  KVM: arm64: vgic-v3: Add ICV_HPPIR1_EL1 handler
  KVM: arm64: vgic-v3: Enable trapping of Group-1 system registers
  KVM: arm64: Enable GICv3 Group-1 sysreg trapping via command-line
  KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler
  KVM: arm64: vgic-v3: Add ICV_IGNREN0_EL1 handler
  KVM: arm64: vgic-v3: Add misc Group-0 handlers
  KVM: arm64: vgic-v3: Enable trapping of Group-0 system registers
  KVM: arm64: Enable GICv3 Group-0 sysreg trapping via command-line
  KVM: arm64: vgic-v3: Add ICV_DIR_EL1 handler
  KVM: arm64: vgic-v3: Add ICV_RPR_EL1 handler
  KVM: arm64: vgic-v3: Add ICV_CTLR_EL1 handler
  KVM: arm64: vgic-v3: Add ICV_PMR_EL1 handler
  KVM: arm64: Enable GICv3 common sysreg trapping via command-line
  KVM: arm64: vgic-v3: Log which GICv3 system registers are trapped

 Documentation/arm64/silicon-errata.txt |   1 +
 arch/arm64/Kconfig                     |  11 +
 arch/arm64/include/asm/cpucaps.h       |   3 +-
 arch/arm64/include/asm/cputype.h       |   2 +
 arch/arm64/include/asm/esr.h           |  24 +
 arch/arm64/include/asm/kvm_hyp.h       |   1 +
 arch/arm64/include/asm/sysreg.h        |   9 +
 arch/arm64/kernel/cpu_errata.c         |  21 +
 arch/arm64/kvm/hyp/switch.c            |  14 +
 include/kvm/arm_vgic.h                 |   1 +
 include/linux/irqchip/arm-gic-v3.h     |   6 +
 virt/kvm/arm/aarch32.c                 |   2 +-
 virt/kvm/arm/hyp/vgic-v3-sr.c          | 803 ++++++++++++++++++++++++++++++++-
 virt/kvm/arm/vgic/vgic-v3.c            |  45 ++
 14 files changed, 925 insertions(+), 18 deletions(-)

-- 
2.11.0

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

* [PATCH v2 00/25] arm64: KVM: Mediate access to GICv3 sysregs at EL2
@ 2017-06-01 10:20 ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

Some systems have less than perfect GICv3 implementations, leading to
all kind of ugly issues (guest hanging, host dying). In order to allow
some level of diagnostic, and in some cases implement workarounds,
this series enables the trapping of both Group-0, Group-1 and Common
sysregs. Mediating the access at EL2 allows some form of sanity
checking that the HW is sometimes sorely lacking.

Instead of fully emulating a GICv3 CPU interface, we still use the
existing HW (list registers, AP registers, VMCR...), which allows the
code to be independent from the rest of the KVM code, and to cope with
partial trapping.

Of course, trapping has a cost, which is why this must be either
enabled on the command line, or selected by another cpu capability
(see Cavium erratum 30115). A quick test on an A57-based platform
shows a 25% hit when repeatedly banging on the trapped registers,
while normal workloads do not seem to suffer noticeably from such
trapping (hackbench variance is in the usual noise, despite being very
IPI happy).

This has been tested on a dual socket Thundex-X and a Freescale LS-2085a.

I've taken the liberty to rebase David Daney's initial Cavium erratum
30115 workaround on top of this series, and included it here as a
typical use case.

- From v1:
  * Fix bug in DIR handling which would have performed a deactivation even
    when EOImode==0
  * Some minor cleanups and clarifications.
  * All the initial fixes have already been merged.
  * Rebased on 4.12-rc3.

David Daney (2):
  arm64: Add MIDR values for Cavium cn83XX SoCs
  arm64: Add workaround for Cavium Thunder erratum 30115

Marc Zyngier (23):
  arm64: Add a facility to turn an ESR syndrome into a sysreg encoding
  KVM: arm/arm64: vgic-v3: Add accessors for the ICH_APxRn_EL2 registers
  KVM: arm64: Make kvm_condition_valid32() accessible from EL2
  KVM: arm64: vgic-v3: Add hook to handle guest GICv3 sysreg accesses at
    EL2
  KVM: arm64: vgic-v3: Add ICV_BPR1_EL1 handler
  KVM: arm64: vgic-v3: Add ICV_IGRPEN1_EL1 handler
  KVM: arm64: vgic-v3: Add ICV_IAR1_EL1 handler
  KVM: arm64: vgic-v3: Add ICV_EOIR1_EL1 handler
  KVM: arm64: vgic-v3: Add ICV_AP1Rn_EL1 handler
  KVM: arm64: vgic-v3: Add ICV_HPPIR1_EL1 handler
  KVM: arm64: vgic-v3: Enable trapping of Group-1 system registers
  KVM: arm64: Enable GICv3 Group-1 sysreg trapping via command-line
  KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler
  KVM: arm64: vgic-v3: Add ICV_IGNREN0_EL1 handler
  KVM: arm64: vgic-v3: Add misc Group-0 handlers
  KVM: arm64: vgic-v3: Enable trapping of Group-0 system registers
  KVM: arm64: Enable GICv3 Group-0 sysreg trapping via command-line
  KVM: arm64: vgic-v3: Add ICV_DIR_EL1 handler
  KVM: arm64: vgic-v3: Add ICV_RPR_EL1 handler
  KVM: arm64: vgic-v3: Add ICV_CTLR_EL1 handler
  KVM: arm64: vgic-v3: Add ICV_PMR_EL1 handler
  KVM: arm64: Enable GICv3 common sysreg trapping via command-line
  KVM: arm64: vgic-v3: Log which GICv3 system registers are trapped

 Documentation/arm64/silicon-errata.txt |   1 +
 arch/arm64/Kconfig                     |  11 +
 arch/arm64/include/asm/cpucaps.h       |   3 +-
 arch/arm64/include/asm/cputype.h       |   2 +
 arch/arm64/include/asm/esr.h           |  24 +
 arch/arm64/include/asm/kvm_hyp.h       |   1 +
 arch/arm64/include/asm/sysreg.h        |   9 +
 arch/arm64/kernel/cpu_errata.c         |  21 +
 arch/arm64/kvm/hyp/switch.c            |  14 +
 include/kvm/arm_vgic.h                 |   1 +
 include/linux/irqchip/arm-gic-v3.h     |   6 +
 virt/kvm/arm/aarch32.c                 |   2 +-
 virt/kvm/arm/hyp/vgic-v3-sr.c          | 803 ++++++++++++++++++++++++++++++++-
 virt/kvm/arm/vgic/vgic-v3.c            |  45 ++
 14 files changed, 925 insertions(+), 18 deletions(-)

-- 
2.11.0

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

* [PATCH v2 01/25] arm64: Add a facility to turn an ESR syndrome into a sysreg encoding
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:20   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:20 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: David Daney, Catalin Marinas, Mark Rutland, Robert Richter,
	Eric Auger, kvmarm, linux-arm-kernel, kvm

It is often useful to compare an ESR syndrome reporting the trapping
of a system register with a value matching that system register.

Since encoding both the sysreg and the ESR version seem to be a bit
overkill, let's add a set of macros that convert an ESR value into
the corresponding sysreg encoding.

We handle both AArch32 and AArch64, taking advantage of identical
encodings between system registers and CP15 accessors.

Acked-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/esr.h | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
index 85997c0e5443..e7d8e281ff62 100644
--- a/arch/arm64/include/asm/esr.h
+++ b/arch/arm64/include/asm/esr.h
@@ -19,6 +19,7 @@
 #define __ASM_ESR_H
 
 #include <asm/memory.h>
+#include <asm/sysreg.h>
 
 #define ESR_ELx_EC_UNKNOWN	(0x00)
 #define ESR_ELx_EC_WFx		(0x01)
@@ -181,6 +182,29 @@
 #define ESR_ELx_SYS64_ISS_SYS_CNTFRQ	(ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 0, 14, 0) | \
 					 ESR_ELx_SYS64_ISS_DIR_READ)
 
+#define esr_sys64_to_sysreg(e)					\
+	sys_reg((((e) & ESR_ELx_SYS64_ISS_OP0_MASK) >>		\
+		 ESR_ELx_SYS64_ISS_OP0_SHIFT),			\
+		(((e) & ESR_ELx_SYS64_ISS_OP1_MASK) >>		\
+		 ESR_ELx_SYS64_ISS_OP1_SHIFT),			\
+		(((e) & ESR_ELx_SYS64_ISS_CRN_MASK) >>		\
+		 ESR_ELx_SYS64_ISS_CRN_SHIFT),			\
+		(((e) & ESR_ELx_SYS64_ISS_CRM_MASK) >>		\
+		 ESR_ELx_SYS64_ISS_CRM_SHIFT),			\
+		(((e) & ESR_ELx_SYS64_ISS_OP2_MASK) >>		\
+		 ESR_ELx_SYS64_ISS_OP2_SHIFT))
+
+#define esr_cp15_to_sysreg(e)					\
+	sys_reg(3,						\
+		(((e) & ESR_ELx_SYS64_ISS_OP1_MASK) >>		\
+		 ESR_ELx_SYS64_ISS_OP1_SHIFT),			\
+		(((e) & ESR_ELx_SYS64_ISS_CRN_MASK) >>		\
+		 ESR_ELx_SYS64_ISS_CRN_SHIFT),			\
+		(((e) & ESR_ELx_SYS64_ISS_CRM_MASK) >>		\
+		 ESR_ELx_SYS64_ISS_CRM_SHIFT),			\
+		(((e) & ESR_ELx_SYS64_ISS_OP2_MASK) >>		\
+		 ESR_ELx_SYS64_ISS_OP2_SHIFT))
+
 #ifndef __ASSEMBLY__
 #include <asm/types.h>
 
-- 
2.11.0

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

* [PATCH v2 01/25] arm64: Add a facility to turn an ESR syndrome into a sysreg encoding
@ 2017-06-01 10:20   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

It is often useful to compare an ESR syndrome reporting the trapping
of a system register with a value matching that system register.

Since encoding both the sysreg and the ESR version seem to be a bit
overkill, let's add a set of macros that convert an ESR value into
the corresponding sysreg encoding.

We handle both AArch32 and AArch64, taking advantage of identical
encodings between system registers and CP15 accessors.

Acked-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/esr.h | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
index 85997c0e5443..e7d8e281ff62 100644
--- a/arch/arm64/include/asm/esr.h
+++ b/arch/arm64/include/asm/esr.h
@@ -19,6 +19,7 @@
 #define __ASM_ESR_H
 
 #include <asm/memory.h>
+#include <asm/sysreg.h>
 
 #define ESR_ELx_EC_UNKNOWN	(0x00)
 #define ESR_ELx_EC_WFx		(0x01)
@@ -181,6 +182,29 @@
 #define ESR_ELx_SYS64_ISS_SYS_CNTFRQ	(ESR_ELx_SYS64_ISS_SYS_VAL(3, 3, 0, 14, 0) | \
 					 ESR_ELx_SYS64_ISS_DIR_READ)
 
+#define esr_sys64_to_sysreg(e)					\
+	sys_reg((((e) & ESR_ELx_SYS64_ISS_OP0_MASK) >>		\
+		 ESR_ELx_SYS64_ISS_OP0_SHIFT),			\
+		(((e) & ESR_ELx_SYS64_ISS_OP1_MASK) >>		\
+		 ESR_ELx_SYS64_ISS_OP1_SHIFT),			\
+		(((e) & ESR_ELx_SYS64_ISS_CRN_MASK) >>		\
+		 ESR_ELx_SYS64_ISS_CRN_SHIFT),			\
+		(((e) & ESR_ELx_SYS64_ISS_CRM_MASK) >>		\
+		 ESR_ELx_SYS64_ISS_CRM_SHIFT),			\
+		(((e) & ESR_ELx_SYS64_ISS_OP2_MASK) >>		\
+		 ESR_ELx_SYS64_ISS_OP2_SHIFT))
+
+#define esr_cp15_to_sysreg(e)					\
+	sys_reg(3,						\
+		(((e) & ESR_ELx_SYS64_ISS_OP1_MASK) >>		\
+		 ESR_ELx_SYS64_ISS_OP1_SHIFT),			\
+		(((e) & ESR_ELx_SYS64_ISS_CRN_MASK) >>		\
+		 ESR_ELx_SYS64_ISS_CRN_SHIFT),			\
+		(((e) & ESR_ELx_SYS64_ISS_CRM_MASK) >>		\
+		 ESR_ELx_SYS64_ISS_CRM_SHIFT),			\
+		(((e) & ESR_ELx_SYS64_ISS_OP2_MASK) >>		\
+		 ESR_ELx_SYS64_ISS_OP2_SHIFT))
+
 #ifndef __ASSEMBLY__
 #include <asm/types.h>
 
-- 
2.11.0

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

* [PATCH v2 02/25] KVM: arm/arm64: vgic-v3: Add accessors for the ICH_APxRn_EL2 registers
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:20   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:20 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: David Daney, Catalin Marinas, Mark Rutland, Robert Richter,
	Eric Auger, kvmarm, linux-arm-kernel, kvm

As we're about to access the Active Priority registers a lot more,
let's define accessors that take the register number as a parameter.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/hyp/vgic-v3-sr.c | 116 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 100 insertions(+), 16 deletions(-)

diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 32c3295929b0..990d9d1e85d0 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -118,6 +118,90 @@ static void __hyp_text __gic_v3_set_lr(u64 val, int lr)
 	}
 }
 
+static void __hyp_text __vgic_v3_write_ap0rn(u32 val, int n)
+{
+	switch (n) {
+	case 0:
+		write_gicreg(val, ICH_AP0R0_EL2);
+		break;
+	case 1:
+		write_gicreg(val, ICH_AP0R1_EL2);
+		break;
+	case 2:
+		write_gicreg(val, ICH_AP0R2_EL2);
+		break;
+	case 3:
+		write_gicreg(val, ICH_AP0R3_EL2);
+		break;
+	}
+}
+
+static void __hyp_text __vgic_v3_write_ap1rn(u32 val, int n)
+{
+	switch (n) {
+	case 0:
+		write_gicreg(val, ICH_AP1R0_EL2);
+		break;
+	case 1:
+		write_gicreg(val, ICH_AP1R1_EL2);
+		break;
+	case 2:
+		write_gicreg(val, ICH_AP1R2_EL2);
+		break;
+	case 3:
+		write_gicreg(val, ICH_AP1R3_EL2);
+		break;
+	}
+}
+
+static u32 __hyp_text __vgic_v3_read_ap0rn(int n)
+{
+	u32 val;
+
+	switch (n) {
+	case 0:
+		val = read_gicreg(ICH_AP0R0_EL2);
+		break;
+	case 1:
+		val = read_gicreg(ICH_AP0R1_EL2);
+		break;
+	case 2:
+		val = read_gicreg(ICH_AP0R2_EL2);
+		break;
+	case 3:
+		val = read_gicreg(ICH_AP0R3_EL2);
+		break;
+	default:
+		unreachable();
+	}
+
+	return val;
+}
+
+static u32 __hyp_text __vgic_v3_read_ap1rn(int n)
+{
+	u32 val;
+
+	switch (n) {
+	case 0:
+		val = read_gicreg(ICH_AP1R0_EL2);
+		break;
+	case 1:
+		val = read_gicreg(ICH_AP1R1_EL2);
+		break;
+	case 2:
+		val = read_gicreg(ICH_AP1R2_EL2);
+		break;
+	case 3:
+		val = read_gicreg(ICH_AP1R3_EL2);
+		break;
+	default:
+		unreachable();
+	}
+
+	return val;
+}
+
 void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
@@ -154,22 +238,22 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 
 		switch (nr_pre_bits) {
 		case 7:
-			cpu_if->vgic_ap0r[3] = read_gicreg(ICH_AP0R3_EL2);
-			cpu_if->vgic_ap0r[2] = read_gicreg(ICH_AP0R2_EL2);
+			cpu_if->vgic_ap0r[3] = __vgic_v3_read_ap0rn(3);
+			cpu_if->vgic_ap0r[2] = __vgic_v3_read_ap0rn(2);
 		case 6:
-			cpu_if->vgic_ap0r[1] = read_gicreg(ICH_AP0R1_EL2);
+			cpu_if->vgic_ap0r[1] = __vgic_v3_read_ap0rn(1);
 		default:
-			cpu_if->vgic_ap0r[0] = read_gicreg(ICH_AP0R0_EL2);
+			cpu_if->vgic_ap0r[0] = __vgic_v3_read_ap0rn(0);
 		}
 
 		switch (nr_pre_bits) {
 		case 7:
-			cpu_if->vgic_ap1r[3] = read_gicreg(ICH_AP1R3_EL2);
-			cpu_if->vgic_ap1r[2] = read_gicreg(ICH_AP1R2_EL2);
+			cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3);
+			cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2);
 		case 6:
-			cpu_if->vgic_ap1r[1] = read_gicreg(ICH_AP1R1_EL2);
+			cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1);
 		default:
-			cpu_if->vgic_ap1r[0] = read_gicreg(ICH_AP1R0_EL2);
+			cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0);
 		}
 	} else {
 		cpu_if->vgic_elrsr = 0xffff;
@@ -224,22 +308,22 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 
 		switch (nr_pre_bits) {
 		case 7:
-			write_gicreg(cpu_if->vgic_ap0r[3], ICH_AP0R3_EL2);
-			write_gicreg(cpu_if->vgic_ap0r[2], ICH_AP0R2_EL2);
+			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[3], 3);
+			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[2], 2);
 		case 6:
-			write_gicreg(cpu_if->vgic_ap0r[1], ICH_AP0R1_EL2);
+			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[1], 1);
 		default:
-			write_gicreg(cpu_if->vgic_ap0r[0], ICH_AP0R0_EL2);
+			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[0], 0);
 		}
 
 		switch (nr_pre_bits) {
 		case 7:
-			write_gicreg(cpu_if->vgic_ap1r[3], ICH_AP1R3_EL2);
-			write_gicreg(cpu_if->vgic_ap1r[2], ICH_AP1R2_EL2);
+			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3);
+			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2);
 		case 6:
-			write_gicreg(cpu_if->vgic_ap1r[1], ICH_AP1R1_EL2);
+			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1);
 		default:
-			write_gicreg(cpu_if->vgic_ap1r[0], ICH_AP1R0_EL2);
+			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0);
 		}
 
 		for (i = 0; i < used_lrs; i++)
-- 
2.11.0

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

* [PATCH v2 02/25] KVM: arm/arm64: vgic-v3: Add accessors for the ICH_APxRn_EL2 registers
@ 2017-06-01 10:20   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

As we're about to access the Active Priority registers a lot more,
let's define accessors that take the register number as a parameter.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/hyp/vgic-v3-sr.c | 116 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 100 insertions(+), 16 deletions(-)

diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 32c3295929b0..990d9d1e85d0 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -118,6 +118,90 @@ static void __hyp_text __gic_v3_set_lr(u64 val, int lr)
 	}
 }
 
+static void __hyp_text __vgic_v3_write_ap0rn(u32 val, int n)
+{
+	switch (n) {
+	case 0:
+		write_gicreg(val, ICH_AP0R0_EL2);
+		break;
+	case 1:
+		write_gicreg(val, ICH_AP0R1_EL2);
+		break;
+	case 2:
+		write_gicreg(val, ICH_AP0R2_EL2);
+		break;
+	case 3:
+		write_gicreg(val, ICH_AP0R3_EL2);
+		break;
+	}
+}
+
+static void __hyp_text __vgic_v3_write_ap1rn(u32 val, int n)
+{
+	switch (n) {
+	case 0:
+		write_gicreg(val, ICH_AP1R0_EL2);
+		break;
+	case 1:
+		write_gicreg(val, ICH_AP1R1_EL2);
+		break;
+	case 2:
+		write_gicreg(val, ICH_AP1R2_EL2);
+		break;
+	case 3:
+		write_gicreg(val, ICH_AP1R3_EL2);
+		break;
+	}
+}
+
+static u32 __hyp_text __vgic_v3_read_ap0rn(int n)
+{
+	u32 val;
+
+	switch (n) {
+	case 0:
+		val = read_gicreg(ICH_AP0R0_EL2);
+		break;
+	case 1:
+		val = read_gicreg(ICH_AP0R1_EL2);
+		break;
+	case 2:
+		val = read_gicreg(ICH_AP0R2_EL2);
+		break;
+	case 3:
+		val = read_gicreg(ICH_AP0R3_EL2);
+		break;
+	default:
+		unreachable();
+	}
+
+	return val;
+}
+
+static u32 __hyp_text __vgic_v3_read_ap1rn(int n)
+{
+	u32 val;
+
+	switch (n) {
+	case 0:
+		val = read_gicreg(ICH_AP1R0_EL2);
+		break;
+	case 1:
+		val = read_gicreg(ICH_AP1R1_EL2);
+		break;
+	case 2:
+		val = read_gicreg(ICH_AP1R2_EL2);
+		break;
+	case 3:
+		val = read_gicreg(ICH_AP1R3_EL2);
+		break;
+	default:
+		unreachable();
+	}
+
+	return val;
+}
+
 void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
@@ -154,22 +238,22 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 
 		switch (nr_pre_bits) {
 		case 7:
-			cpu_if->vgic_ap0r[3] = read_gicreg(ICH_AP0R3_EL2);
-			cpu_if->vgic_ap0r[2] = read_gicreg(ICH_AP0R2_EL2);
+			cpu_if->vgic_ap0r[3] = __vgic_v3_read_ap0rn(3);
+			cpu_if->vgic_ap0r[2] = __vgic_v3_read_ap0rn(2);
 		case 6:
-			cpu_if->vgic_ap0r[1] = read_gicreg(ICH_AP0R1_EL2);
+			cpu_if->vgic_ap0r[1] = __vgic_v3_read_ap0rn(1);
 		default:
-			cpu_if->vgic_ap0r[0] = read_gicreg(ICH_AP0R0_EL2);
+			cpu_if->vgic_ap0r[0] = __vgic_v3_read_ap0rn(0);
 		}
 
 		switch (nr_pre_bits) {
 		case 7:
-			cpu_if->vgic_ap1r[3] = read_gicreg(ICH_AP1R3_EL2);
-			cpu_if->vgic_ap1r[2] = read_gicreg(ICH_AP1R2_EL2);
+			cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3);
+			cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2);
 		case 6:
-			cpu_if->vgic_ap1r[1] = read_gicreg(ICH_AP1R1_EL2);
+			cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1);
 		default:
-			cpu_if->vgic_ap1r[0] = read_gicreg(ICH_AP1R0_EL2);
+			cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0);
 		}
 	} else {
 		cpu_if->vgic_elrsr = 0xffff;
@@ -224,22 +308,22 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 
 		switch (nr_pre_bits) {
 		case 7:
-			write_gicreg(cpu_if->vgic_ap0r[3], ICH_AP0R3_EL2);
-			write_gicreg(cpu_if->vgic_ap0r[2], ICH_AP0R2_EL2);
+			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[3], 3);
+			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[2], 2);
 		case 6:
-			write_gicreg(cpu_if->vgic_ap0r[1], ICH_AP0R1_EL2);
+			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[1], 1);
 		default:
-			write_gicreg(cpu_if->vgic_ap0r[0], ICH_AP0R0_EL2);
+			__vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[0], 0);
 		}
 
 		switch (nr_pre_bits) {
 		case 7:
-			write_gicreg(cpu_if->vgic_ap1r[3], ICH_AP1R3_EL2);
-			write_gicreg(cpu_if->vgic_ap1r[2], ICH_AP1R2_EL2);
+			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3);
+			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2);
 		case 6:
-			write_gicreg(cpu_if->vgic_ap1r[1], ICH_AP1R1_EL2);
+			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1);
 		default:
-			write_gicreg(cpu_if->vgic_ap1r[0], ICH_AP1R0_EL2);
+			__vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0);
 		}
 
 		for (i = 0; i < used_lrs; i++)
-- 
2.11.0

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

* [PATCH v2 03/25] KVM: arm64: Make kvm_condition_valid32() accessible from EL2
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:20   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:20 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter, kvmarm,
	linux-arm-kernel

As we're about to trap CP15 accesses and handle them at EL2, we
need to evaluate whether or not the condition flags are valid,
as an implementation is allowed to trap despite the condition
not being met.

Tagging the function as __hyp_text allows this.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/aarch32.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/virt/kvm/arm/aarch32.c b/virt/kvm/arm/aarch32.c
index 528af4b2d09e..79c7c357804b 100644
--- a/virt/kvm/arm/aarch32.c
+++ b/virt/kvm/arm/aarch32.c
@@ -60,7 +60,7 @@ static const unsigned short cc_map[16] = {
 /*
  * Check if a trapped instruction should have been executed or not.
  */
-bool kvm_condition_valid32(const struct kvm_vcpu *vcpu)
+bool __hyp_text kvm_condition_valid32(const struct kvm_vcpu *vcpu)
 {
 	unsigned long cpsr;
 	u32 cpsr_cond;
-- 
2.11.0

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

* [PATCH v2 03/25] KVM: arm64: Make kvm_condition_valid32() accessible from EL2
@ 2017-06-01 10:20   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

As we're about to trap CP15 accesses and handle them at EL2, we
need to evaluate whether or not the condition flags are valid,
as an implementation is allowed to trap despite the condition
not being met.

Tagging the function as __hyp_text allows this.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/aarch32.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/virt/kvm/arm/aarch32.c b/virt/kvm/arm/aarch32.c
index 528af4b2d09e..79c7c357804b 100644
--- a/virt/kvm/arm/aarch32.c
+++ b/virt/kvm/arm/aarch32.c
@@ -60,7 +60,7 @@ static const unsigned short cc_map[16] = {
 /*
  * Check if a trapped instruction should have been executed or not.
  */
-bool kvm_condition_valid32(const struct kvm_vcpu *vcpu)
+bool __hyp_text kvm_condition_valid32(const struct kvm_vcpu *vcpu)
 {
 	unsigned long cpsr;
 	u32 cpsr_cond;
-- 
2.11.0

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

* [PATCH v2 04/25] KVM: arm64: vgic-v3: Add hook to handle guest GICv3 sysreg accesses at EL2
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:20   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:20 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: David Daney, Catalin Marinas, Mark Rutland, Robert Richter,
	Eric Auger, kvmarm, linux-arm-kernel, kvm

In order to start handling guest access to GICv3 system registers,
let's add a hook that will get called when we trap a system register
access. This is gated by a new static key (vgic_v3_cpuif_trap).

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/kvm_hyp.h |  1 +
 arch/arm64/kvm/hyp/switch.c      | 14 ++++++++++++++
 include/kvm/arm_vgic.h           |  1 +
 virt/kvm/arm/hyp/vgic-v3-sr.c    | 38 ++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c      |  2 ++
 5 files changed, 56 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index b18e852d27e8..4572a9b560fa 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -127,6 +127,7 @@ 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);
+int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
 
 void __timer_save_state(struct kvm_vcpu *vcpu);
 void __timer_restore_state(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index aede1658aeda..dfd8ca16601b 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -350,6 +350,20 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 		}
 	}
 
+	if (static_branch_unlikely(&vgic_v3_cpuif_trap) &&
+	    exit_code == ARM_EXCEPTION_TRAP &&
+	    (kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_SYS64 ||
+	     kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_CP15_32)) {
+		int ret = __vgic_v3_perform_cpuif_access(vcpu);
+
+		if (ret == 1) {
+			__skip_instr(vcpu);
+			goto again;
+		}
+
+		/* 0 falls through to be handled out of EL2 */
+	}
+
 	fp_enabled = __fpsimd_enabled();
 
 	__sysreg_save_guest_state(guest_ctxt);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index ef718586321c..39b9fc4dc65d 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -285,6 +285,7 @@ struct vgic_cpu {
 };
 
 extern struct static_key_false vgic_v2_cpuif_trap;
+extern struct static_key_false vgic_v3_cpuif_trap;
 
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
 void kvm_vgic_early_init(struct kvm *kvm);
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 990d9d1e85d0..943bf11252d9 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -19,6 +19,7 @@
 #include <linux/irqchip/arm-gic-v3.h>
 #include <linux/kvm_host.h>
 
+#include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
 
 #define vtr_to_max_lr_idx(v)		((v) & 0xf)
@@ -371,3 +372,40 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
 {
 	write_gicreg(vmcr, ICH_VMCR_EL2);
 }
+
+#ifdef CONFIG_ARM64
+
+int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
+{
+	int rt;
+	u32 esr;
+	u32 vmcr;
+	void (*fn)(struct kvm_vcpu *, u32, int);
+	bool is_read;
+	u32 sysreg;
+
+	esr = kvm_vcpu_get_hsr(vcpu);
+	if (vcpu_mode_is_32bit(vcpu)) {
+		if (!kvm_condition_valid(vcpu))
+			return 1;
+
+		sysreg = esr_cp15_to_sysreg(esr);
+	} else {
+		sysreg = esr_sys64_to_sysreg(esr);
+	}
+
+	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
+
+	switch (sysreg) {
+	default:
+		return 0;
+	}
+
+	vmcr = __vgic_v3_read_vmcr();
+	rt = kvm_vcpu_sys_get_rt(vcpu);
+	fn(vcpu, vmcr, rt);
+
+	return 1;
+}
+
+#endif
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 6fe3f003636a..88d9bd9bf468 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -410,6 +410,8 @@ int vgic_v3_map_resources(struct kvm *kvm)
 	return ret;
 }
 
+DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap);
+
 /**
  * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
  * @node:	pointer to the DT node
-- 
2.11.0

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

* [PATCH v2 04/25] KVM: arm64: vgic-v3: Add hook to handle guest GICv3 sysreg accesses at EL2
@ 2017-06-01 10:20   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

In order to start handling guest access to GICv3 system registers,
let's add a hook that will get called when we trap a system register
access. This is gated by a new static key (vgic_v3_cpuif_trap).

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/kvm_hyp.h |  1 +
 arch/arm64/kvm/hyp/switch.c      | 14 ++++++++++++++
 include/kvm/arm_vgic.h           |  1 +
 virt/kvm/arm/hyp/vgic-v3-sr.c    | 38 ++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c      |  2 ++
 5 files changed, 56 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index b18e852d27e8..4572a9b560fa 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -127,6 +127,7 @@ 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);
+int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
 
 void __timer_save_state(struct kvm_vcpu *vcpu);
 void __timer_restore_state(struct kvm_vcpu *vcpu);
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index aede1658aeda..dfd8ca16601b 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -350,6 +350,20 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 		}
 	}
 
+	if (static_branch_unlikely(&vgic_v3_cpuif_trap) &&
+	    exit_code == ARM_EXCEPTION_TRAP &&
+	    (kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_SYS64 ||
+	     kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_CP15_32)) {
+		int ret = __vgic_v3_perform_cpuif_access(vcpu);
+
+		if (ret == 1) {
+			__skip_instr(vcpu);
+			goto again;
+		}
+
+		/* 0 falls through to be handled out of EL2 */
+	}
+
 	fp_enabled = __fpsimd_enabled();
 
 	__sysreg_save_guest_state(guest_ctxt);
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index ef718586321c..39b9fc4dc65d 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -285,6 +285,7 @@ struct vgic_cpu {
 };
 
 extern struct static_key_false vgic_v2_cpuif_trap;
+extern struct static_key_false vgic_v3_cpuif_trap;
 
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
 void kvm_vgic_early_init(struct kvm *kvm);
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 990d9d1e85d0..943bf11252d9 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -19,6 +19,7 @@
 #include <linux/irqchip/arm-gic-v3.h>
 #include <linux/kvm_host.h>
 
+#include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
 
 #define vtr_to_max_lr_idx(v)		((v) & 0xf)
@@ -371,3 +372,40 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
 {
 	write_gicreg(vmcr, ICH_VMCR_EL2);
 }
+
+#ifdef CONFIG_ARM64
+
+int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
+{
+	int rt;
+	u32 esr;
+	u32 vmcr;
+	void (*fn)(struct kvm_vcpu *, u32, int);
+	bool is_read;
+	u32 sysreg;
+
+	esr = kvm_vcpu_get_hsr(vcpu);
+	if (vcpu_mode_is_32bit(vcpu)) {
+		if (!kvm_condition_valid(vcpu))
+			return 1;
+
+		sysreg = esr_cp15_to_sysreg(esr);
+	} else {
+		sysreg = esr_sys64_to_sysreg(esr);
+	}
+
+	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
+
+	switch (sysreg) {
+	default:
+		return 0;
+	}
+
+	vmcr = __vgic_v3_read_vmcr();
+	rt = kvm_vcpu_sys_get_rt(vcpu);
+	fn(vcpu, vmcr, rt);
+
+	return 1;
+}
+
+#endif
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 6fe3f003636a..88d9bd9bf468 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -410,6 +410,8 @@ int vgic_v3_map_resources(struct kvm *kvm)
 	return ret;
 }
 
+DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap);
+
 /**
  * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
  * @node:	pointer to the DT node
-- 
2.11.0

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

* [PATCH v2 05/25] KVM: arm64: vgic-v3: Add ICV_BPR1_EL1 handler
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:20   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:20 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: David Daney, Catalin Marinas, Mark Rutland, Robert Richter,
	Eric Auger, kvmarm, linux-arm-kernel, kvm

Add a handler for reading/writing the guest's view of the ICC_BPR1_EL1
register, which is located in the ICH_VMCR_EL2.BPR1 field.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/hyp/vgic-v3-sr.c | 51 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 943bf11252d9..6254eaf72a77 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -375,6 +375,51 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
 
 #ifdef CONFIG_ARM64
 
+static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
+{
+	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
+}
+
+static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
+{
+	unsigned int bpr;
+
+	if (vmcr & ICH_VMCR_CBPR_MASK) {
+		bpr = __vgic_v3_get_bpr0(vmcr);
+		if (bpr < 7)
+			bpr++;
+	} else {
+		bpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
+	}
+
+	return bpr;
+}
+
+static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
+{
+	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
+}
+
+static void __hyp_text __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
+{
+	u64 val = vcpu_get_reg(vcpu, rt);
+	u8 bpr_min = 8 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
+
+	if (vmcr & ICH_VMCR_CBPR_MASK)
+		return;
+
+	/* Enforce BPR limiting */
+	if (val < bpr_min)
+		val = bpr_min;
+
+	val <<= ICH_VMCR_BPR1_SHIFT;
+	val &= ICH_VMCR_BPR1_MASK;
+	vmcr &= ~ICH_VMCR_BPR1_MASK;
+	vmcr |= val;
+
+	__vgic_v3_write_vmcr(vmcr);
+}
+
 int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 {
 	int rt;
@@ -397,6 +442,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
 
 	switch (sysreg) {
+	case SYS_ICC_BPR1_EL1:
+		if (is_read)
+			fn = __vgic_v3_read_bpr1;
+		else
+			fn = __vgic_v3_write_bpr1;
+		break;
 	default:
 		return 0;
 	}
-- 
2.11.0

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

* [PATCH v2 05/25] KVM: arm64: vgic-v3: Add ICV_BPR1_EL1 handler
@ 2017-06-01 10:20   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

Add a handler for reading/writing the guest's view of the ICC_BPR1_EL1
register, which is located in the ICH_VMCR_EL2.BPR1 field.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/hyp/vgic-v3-sr.c | 51 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 943bf11252d9..6254eaf72a77 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -375,6 +375,51 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
 
 #ifdef CONFIG_ARM64
 
+static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
+{
+	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
+}
+
+static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
+{
+	unsigned int bpr;
+
+	if (vmcr & ICH_VMCR_CBPR_MASK) {
+		bpr = __vgic_v3_get_bpr0(vmcr);
+		if (bpr < 7)
+			bpr++;
+	} else {
+		bpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
+	}
+
+	return bpr;
+}
+
+static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
+{
+	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
+}
+
+static void __hyp_text __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
+{
+	u64 val = vcpu_get_reg(vcpu, rt);
+	u8 bpr_min = 8 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
+
+	if (vmcr & ICH_VMCR_CBPR_MASK)
+		return;
+
+	/* Enforce BPR limiting */
+	if (val < bpr_min)
+		val = bpr_min;
+
+	val <<= ICH_VMCR_BPR1_SHIFT;
+	val &= ICH_VMCR_BPR1_MASK;
+	vmcr &= ~ICH_VMCR_BPR1_MASK;
+	vmcr |= val;
+
+	__vgic_v3_write_vmcr(vmcr);
+}
+
 int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 {
 	int rt;
@@ -397,6 +442,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
 
 	switch (sysreg) {
+	case SYS_ICC_BPR1_EL1:
+		if (is_read)
+			fn = __vgic_v3_read_bpr1;
+		else
+			fn = __vgic_v3_write_bpr1;
+		break;
 	default:
 		return 0;
 	}
-- 
2.11.0

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

* [PATCH v2 06/25] KVM: arm64: vgic-v3: Add ICV_IGRPEN1_EL1 handler
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:20   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:20 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter, kvmarm,
	linux-arm-kernel

Add a handler for reading/writing the guest's view of the ICC_IGRPEN1_EL1
register, which is located in the ICH_VMCR_EL2.VENG1 field.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/hyp/vgic-v3-sr.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 6254eaf72a77..168539dfd0b9 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -395,6 +395,23 @@ static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
 	return bpr;
 }
 
+static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
+{
+	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
+}
+
+static void __hyp_text __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
+{
+	u64 val = vcpu_get_reg(vcpu, rt);
+
+	if (val & 1)
+		vmcr |= ICH_VMCR_ENG1_MASK;
+	else
+		vmcr &= ~ICH_VMCR_ENG1_MASK;
+
+	__vgic_v3_write_vmcr(vmcr);
+}
+
 static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
 	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
@@ -442,6 +459,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
 
 	switch (sysreg) {
+	case SYS_ICC_GRPEN1_EL1:
+		if (is_read)
+			fn = __vgic_v3_read_igrpen1;
+		else
+			fn = __vgic_v3_write_igrpen1;
+		break;
 	case SYS_ICC_BPR1_EL1:
 		if (is_read)
 			fn = __vgic_v3_read_bpr1;
-- 
2.11.0

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

* [PATCH v2 06/25] KVM: arm64: vgic-v3: Add ICV_IGRPEN1_EL1 handler
@ 2017-06-01 10:20   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

Add a handler for reading/writing the guest's view of the ICC_IGRPEN1_EL1
register, which is located in the ICH_VMCR_EL2.VENG1 field.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/hyp/vgic-v3-sr.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 6254eaf72a77..168539dfd0b9 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -395,6 +395,23 @@ static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
 	return bpr;
 }
 
+static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
+{
+	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
+}
+
+static void __hyp_text __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
+{
+	u64 val = vcpu_get_reg(vcpu, rt);
+
+	if (val & 1)
+		vmcr |= ICH_VMCR_ENG1_MASK;
+	else
+		vmcr &= ~ICH_VMCR_ENG1_MASK;
+
+	__vgic_v3_write_vmcr(vmcr);
+}
+
 static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
 	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
@@ -442,6 +459,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
 
 	switch (sysreg) {
+	case SYS_ICC_GRPEN1_EL1:
+		if (is_read)
+			fn = __vgic_v3_read_igrpen1;
+		else
+			fn = __vgic_v3_write_igrpen1;
+		break;
 	case SYS_ICC_BPR1_EL1:
 		if (is_read)
 			fn = __vgic_v3_read_bpr1;
-- 
2.11.0

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

* [PATCH v2 07/25] KVM: arm64: vgic-v3: Add ICV_IAR1_EL1 handler
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:20   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:20 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: David Daney, Catalin Marinas, Mark Rutland, Robert Richter,
	Eric Auger, kvmarm, linux-arm-kernel, kvm

Add a handler for reading the guest's view of the ICC_IAR1_EL1
register. This involves finding the highest priority Group-1
interrupt, checking against both PMR and the active group
priority, activating the interrupt and setting the group
priority as active.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/linux/irqchip/arm-gic-v3.h |   1 +
 virt/kvm/arm/hyp/vgic-v3-sr.c      | 150 +++++++++++++++++++++++++++++++++++++
 2 files changed, 151 insertions(+)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index fffb91202bc9..401db585a534 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -405,6 +405,7 @@
 #define ICH_LR_PHYS_ID_SHIFT		32
 #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
 #define ICH_LR_PRIORITY_SHIFT		48
+#define ICH_LR_PRIORITY_MASK		(0xffULL << ICH_LR_PRIORITY_SHIFT)
 
 /* These are for GICv2 emulation only */
 #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 168539dfd0b9..16a2eadc7a5c 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -24,6 +24,7 @@
 
 #define vtr_to_max_lr_idx(v)		((v) & 0xf)
 #define vtr_to_nr_pre_bits(v)		(((u32)(v) >> 26) + 1)
+#define vtr_to_nr_apr_regs(v)		(1 << (vtr_to_nr_pre_bits(v) - 5))
 
 static u64 __hyp_text __gic_v3_get_lr(unsigned int lr)
 {
@@ -375,6 +376,79 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
 
 #ifdef CONFIG_ARM64
 
+static int __hyp_text __vgic_v3_get_group(struct kvm_vcpu *vcpu)
+{
+	u32 esr = kvm_vcpu_get_hsr(vcpu);
+	u8 crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT;
+
+	return crm != 8;
+}
+
+#define GICv3_IDLE_PRIORITY	0xff
+
+static int __hyp_text __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu,
+						    u32 vmcr,
+						    u64 *lr_val)
+{
+	unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
+	u8 priority = GICv3_IDLE_PRIORITY;
+	int i, lr = -1;
+
+	for (i = 0; i < used_lrs; i++) {
+		u64 val = __gic_v3_get_lr(i);
+		u8 lr_prio = (val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
+
+		/* Not pending in the state? */
+		if ((val & ICH_LR_STATE) != ICH_LR_PENDING_BIT)
+			continue;
+
+		/* Group-0 interrupt, but Group-0 disabled? */
+		if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG0_MASK))
+			continue;
+
+		/* Group-1 interrupt, but Group-1 disabled? */
+		if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG1_MASK))
+			continue;
+
+		/* Not the highest priority? */
+		if (lr_prio >= priority)
+			continue;
+
+		/* This is a candidate */
+		priority = lr_prio;
+		*lr_val = val;
+		lr = i;
+	}
+
+	if (lr == -1)
+		*lr_val = ICC_IAR1_EL1_SPURIOUS;
+
+	return lr;
+}
+
+static int __hyp_text __vgic_v3_get_highest_active_priority(void)
+{
+	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
+	u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
+	u32 hap = 0;
+	int i;
+
+	for (i = 0; i < nr_apr_regs; i++) {
+		u32 val;
+
+		val  = __vgic_v3_read_ap0rn(i);
+		val |= __vgic_v3_read_ap1rn(i);
+		if (!val) {
+			hap += 32;
+			continue;
+		}
+
+		return (hap + __ffs(val)) << (8 - nr_pre_bits);
+	}
+
+	return GICv3_IDLE_PRIORITY;
+}
+
 static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
 {
 	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
@@ -395,6 +469,79 @@ static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
 	return bpr;
 }
 
+/*
+ * Convert a priority to a preemption level, taking the relevant BPR
+ * into account by zeroing the sub-priority bits.
+ */
+static u8 __hyp_text __vgic_v3_pri_to_pre(u8 pri, u32 vmcr, int grp)
+{
+	unsigned int bpr;
+
+	if (!grp)
+		bpr = __vgic_v3_get_bpr0(vmcr) + 1;
+	else
+		bpr = __vgic_v3_get_bpr1(vmcr);
+
+	return pri & (GENMASK(7, 0) << bpr);
+}
+
+/*
+ * The priority value is independent of any of the BPR values, so we
+ * normalize it using nr_pre_bits. This guarantees that no matter what
+ * the guest does with its BPR, we can always set/get the same value
+ * of a priority.
+ */
+static void __hyp_text __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp)
+{
+	u8 nr_pre_bits, pre, ap;
+	u32 val;
+	int apr;
+
+	nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
+	pre = __vgic_v3_pri_to_pre(pri, vmcr, grp);
+	ap = pre >> (8 - nr_pre_bits);
+	apr = ap / 32;
+
+	val = __vgic_v3_read_ap1rn(apr);
+	__vgic_v3_write_ap1rn(val | BIT(ap % 32), apr);
+}
+
+static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
+{
+	u64 lr_val;
+	u8 lr_prio, pmr;
+	int lr, grp;
+
+	grp = __vgic_v3_get_group(vcpu);
+
+	lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
+	if (lr < 0)
+		goto spurious;
+
+	if (grp != !!(lr_val & ICH_LR_GROUP))
+		goto spurious;
+
+	pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
+	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
+	if (pmr <= lr_prio)
+		goto spurious;
+
+	if (__vgic_v3_get_highest_active_priority() <= lr_prio)
+		goto spurious;
+
+	lr_val &= ~ICH_LR_STATE;
+	/* No active state for LPIs */
+	if ((lr_val & ICH_LR_VIRTUAL_ID_MASK) <= VGIC_MAX_SPI)
+		lr_val |= ICH_LR_ACTIVE_BIT;
+	__gic_v3_set_lr(lr_val, lr);
+	__vgic_v3_set_active_priority(lr_prio, vmcr, grp);
+	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
+	return;
+
+spurious:
+	vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS);
+}
+
 static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
 	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
@@ -459,6 +606,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
 
 	switch (sysreg) {
+	case SYS_ICC_IAR1_EL1:
+		fn = __vgic_v3_read_iar;
+		break;
 	case SYS_ICC_GRPEN1_EL1:
 		if (is_read)
 			fn = __vgic_v3_read_igrpen1;
-- 
2.11.0

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

* [PATCH v2 07/25] KVM: arm64: vgic-v3: Add ICV_IAR1_EL1 handler
@ 2017-06-01 10:20   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:20 UTC (permalink / raw)
  To: linux-arm-kernel

Add a handler for reading the guest's view of the ICC_IAR1_EL1
register. This involves finding the highest priority Group-1
interrupt, checking against both PMR and the active group
priority, activating the interrupt and setting the group
priority as active.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/linux/irqchip/arm-gic-v3.h |   1 +
 virt/kvm/arm/hyp/vgic-v3-sr.c      | 150 +++++++++++++++++++++++++++++++++++++
 2 files changed, 151 insertions(+)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index fffb91202bc9..401db585a534 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -405,6 +405,7 @@
 #define ICH_LR_PHYS_ID_SHIFT		32
 #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
 #define ICH_LR_PRIORITY_SHIFT		48
+#define ICH_LR_PRIORITY_MASK		(0xffULL << ICH_LR_PRIORITY_SHIFT)
 
 /* These are for GICv2 emulation only */
 #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 168539dfd0b9..16a2eadc7a5c 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -24,6 +24,7 @@
 
 #define vtr_to_max_lr_idx(v)		((v) & 0xf)
 #define vtr_to_nr_pre_bits(v)		(((u32)(v) >> 26) + 1)
+#define vtr_to_nr_apr_regs(v)		(1 << (vtr_to_nr_pre_bits(v) - 5))
 
 static u64 __hyp_text __gic_v3_get_lr(unsigned int lr)
 {
@@ -375,6 +376,79 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
 
 #ifdef CONFIG_ARM64
 
+static int __hyp_text __vgic_v3_get_group(struct kvm_vcpu *vcpu)
+{
+	u32 esr = kvm_vcpu_get_hsr(vcpu);
+	u8 crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT;
+
+	return crm != 8;
+}
+
+#define GICv3_IDLE_PRIORITY	0xff
+
+static int __hyp_text __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu,
+						    u32 vmcr,
+						    u64 *lr_val)
+{
+	unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
+	u8 priority = GICv3_IDLE_PRIORITY;
+	int i, lr = -1;
+
+	for (i = 0; i < used_lrs; i++) {
+		u64 val = __gic_v3_get_lr(i);
+		u8 lr_prio = (val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
+
+		/* Not pending in the state? */
+		if ((val & ICH_LR_STATE) != ICH_LR_PENDING_BIT)
+			continue;
+
+		/* Group-0 interrupt, but Group-0 disabled? */
+		if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG0_MASK))
+			continue;
+
+		/* Group-1 interrupt, but Group-1 disabled? */
+		if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG1_MASK))
+			continue;
+
+		/* Not the highest priority? */
+		if (lr_prio >= priority)
+			continue;
+
+		/* This is a candidate */
+		priority = lr_prio;
+		*lr_val = val;
+		lr = i;
+	}
+
+	if (lr == -1)
+		*lr_val = ICC_IAR1_EL1_SPURIOUS;
+
+	return lr;
+}
+
+static int __hyp_text __vgic_v3_get_highest_active_priority(void)
+{
+	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
+	u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
+	u32 hap = 0;
+	int i;
+
+	for (i = 0; i < nr_apr_regs; i++) {
+		u32 val;
+
+		val  = __vgic_v3_read_ap0rn(i);
+		val |= __vgic_v3_read_ap1rn(i);
+		if (!val) {
+			hap += 32;
+			continue;
+		}
+
+		return (hap + __ffs(val)) << (8 - nr_pre_bits);
+	}
+
+	return GICv3_IDLE_PRIORITY;
+}
+
 static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
 {
 	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
@@ -395,6 +469,79 @@ static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
 	return bpr;
 }
 
+/*
+ * Convert a priority to a preemption level, taking the relevant BPR
+ * into account by zeroing the sub-priority bits.
+ */
+static u8 __hyp_text __vgic_v3_pri_to_pre(u8 pri, u32 vmcr, int grp)
+{
+	unsigned int bpr;
+
+	if (!grp)
+		bpr = __vgic_v3_get_bpr0(vmcr) + 1;
+	else
+		bpr = __vgic_v3_get_bpr1(vmcr);
+
+	return pri & (GENMASK(7, 0) << bpr);
+}
+
+/*
+ * The priority value is independent of any of the BPR values, so we
+ * normalize it using nr_pre_bits. This guarantees that no matter what
+ * the guest does with its BPR, we can always set/get the same value
+ * of a priority.
+ */
+static void __hyp_text __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp)
+{
+	u8 nr_pre_bits, pre, ap;
+	u32 val;
+	int apr;
+
+	nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
+	pre = __vgic_v3_pri_to_pre(pri, vmcr, grp);
+	ap = pre >> (8 - nr_pre_bits);
+	apr = ap / 32;
+
+	val = __vgic_v3_read_ap1rn(apr);
+	__vgic_v3_write_ap1rn(val | BIT(ap % 32), apr);
+}
+
+static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
+{
+	u64 lr_val;
+	u8 lr_prio, pmr;
+	int lr, grp;
+
+	grp = __vgic_v3_get_group(vcpu);
+
+	lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
+	if (lr < 0)
+		goto spurious;
+
+	if (grp != !!(lr_val & ICH_LR_GROUP))
+		goto spurious;
+
+	pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
+	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
+	if (pmr <= lr_prio)
+		goto spurious;
+
+	if (__vgic_v3_get_highest_active_priority() <= lr_prio)
+		goto spurious;
+
+	lr_val &= ~ICH_LR_STATE;
+	/* No active state for LPIs */
+	if ((lr_val & ICH_LR_VIRTUAL_ID_MASK) <= VGIC_MAX_SPI)
+		lr_val |= ICH_LR_ACTIVE_BIT;
+	__gic_v3_set_lr(lr_val, lr);
+	__vgic_v3_set_active_priority(lr_prio, vmcr, grp);
+	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
+	return;
+
+spurious:
+	vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS);
+}
+
 static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
 	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
@@ -459,6 +606,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
 
 	switch (sysreg) {
+	case SYS_ICC_IAR1_EL1:
+		fn = __vgic_v3_read_iar;
+		break;
 	case SYS_ICC_GRPEN1_EL1:
 		if (is_read)
 			fn = __vgic_v3_read_igrpen1;
-- 
2.11.0

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

* [PATCH v2 08/25] KVM: arm64: vgic-v3: Add ICV_EOIR1_EL1 handler
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:21   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: David Daney, Catalin Marinas, Mark Rutland, Robert Richter,
	Eric Auger, kvmarm, linux-arm-kernel, kvm

Add a handler for writing the guest's view of the ICC_EOIR1_EL1
register. This involves dropping the priority of the interrupt,
and deactivating it if required (EOImode == 0).

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/linux/irqchip/arm-gic-v3.h |   2 +
 virt/kvm/arm/hyp/vgic-v3-sr.c      | 121 +++++++++++++++++++++++++++++++++++++
 2 files changed, 123 insertions(+)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 401db585a534..e50ce5d416a3 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -417,6 +417,8 @@
 
 #define ICH_HCR_EN			(1 << 0)
 #define ICH_HCR_UIE			(1 << 1)
+#define ICH_HCR_EOIcount_SHIFT		27
+#define ICH_HCR_EOIcount_MASK		(0x1f << ICH_HCR_EOIcount_SHIFT)
 
 #define ICH_VMCR_CBPR_SHIFT		4
 #define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 16a2eadc7a5c..3f04122a5d4d 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -426,6 +426,26 @@ static int __hyp_text __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu,
 	return lr;
 }
 
+static int __hyp_text __vgic_v3_find_active_lr(struct kvm_vcpu *vcpu,
+					       int intid, u64 *lr_val)
+{
+	unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
+	int i;
+
+	for (i = 0; i < used_lrs; i++) {
+		u64 val = __gic_v3_get_lr(i);
+
+		if ((val & ICH_LR_VIRTUAL_ID_MASK) == intid &&
+		    (val & ICH_LR_ACTIVE_BIT)) {
+			*lr_val = val;
+			return i;
+		}
+	}
+
+	*lr_val = ICC_IAR1_EL1_SPURIOUS;
+	return -1;
+}
+
 static int __hyp_text __vgic_v3_get_highest_active_priority(void)
 {
 	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
@@ -506,6 +526,45 @@ static void __hyp_text __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp)
 	__vgic_v3_write_ap1rn(val | BIT(ap % 32), apr);
 }
 
+static int __hyp_text __vgic_v3_clear_highest_active_priority(void)
+{
+	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
+	u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
+	u32 hap = 0;
+	int i;
+
+	for (i = 0; i < nr_apr_regs; i++) {
+		u32 ap0, ap1;
+		int c0, c1;
+
+		ap0 = __vgic_v3_read_ap0rn(i);
+		ap1 = __vgic_v3_read_ap1rn(i);
+		if (!ap0 && !ap1) {
+			hap += 32;
+			continue;
+		}
+
+		c0 = ap0 ? __ffs(ap0) : 32;
+		c1 = ap1 ? __ffs(ap1) : 32;
+
+		/* Always clear the LSB, which is the highest priority */
+		if (c0 < c1) {
+			ap0 &= ~BIT(c0);
+			__vgic_v3_write_ap0rn(ap0, i);
+			hap += c0;
+		} else {
+			ap1 &= ~BIT(c1);
+			__vgic_v3_write_ap1rn(ap1, i);
+			hap += c1;
+		}
+
+		/* Rescale to 8 bits of priority */
+		return hap << (8 - nr_pre_bits);
+	}
+
+	return GICv3_IDLE_PRIORITY;
+}
+
 static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
 	u64 lr_val;
@@ -542,6 +601,65 @@ static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int r
 	vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS);
 }
 
+static void __hyp_text __vgic_v3_clear_active_lr(int lr, u64 lr_val)
+{
+	lr_val &= ~ICH_LR_ACTIVE_BIT;
+	if (lr_val & ICH_LR_HW) {
+		u32 pid;
+
+		pid = (lr_val & ICH_LR_PHYS_ID_MASK) >> ICH_LR_PHYS_ID_SHIFT;
+		gic_write_dir(pid);
+	}
+
+	__gic_v3_set_lr(lr_val, lr);
+}
+
+static void __hyp_text __vgic_v3_bump_eoicount(void)
+{
+	u32 hcr;
+
+	hcr = read_gicreg(ICH_HCR_EL2);
+	hcr += 1 << ICH_HCR_EOIcount_SHIFT;
+	write_gicreg(hcr, ICH_HCR_EL2);
+}
+
+static void __hyp_text __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
+{
+	u32 vid = vcpu_get_reg(vcpu, rt);
+	u64 lr_val;
+	u8 lr_prio, act_prio;
+	int lr, grp;
+
+	grp = __vgic_v3_get_group(vcpu);
+
+	/* Drop priority in any case */
+	act_prio = __vgic_v3_clear_highest_active_priority();
+
+	/* If EOIing an LPI, no deactivate to be performed */
+	if (vid >= VGIC_MIN_LPI)
+		return;
+
+	/* EOImode == 1, nothing to be done here */
+	if (vmcr & ICH_VMCR_EOIM_MASK)
+		return;
+
+	lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val);
+	if (lr == -1) {
+		__vgic_v3_bump_eoicount();
+		return;
+	}
+
+	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
+
+	/* If priorities or group do not match, the guest has fscked-up. */
+	if (grp != !!(lr_val & ICH_LR_GROUP) ||
+	    __vgic_v3_pri_to_pre(lr_prio, vmcr, grp) != act_prio)
+		return;
+
+	/* Let's now perform the deactivation */
+	__vgic_v3_clear_active_lr(lr, lr_val);
+}
+
 static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
 	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
@@ -609,6 +727,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 	case SYS_ICC_IAR1_EL1:
 		fn = __vgic_v3_read_iar;
 		break;
+	case SYS_ICC_EOIR1_EL1:
+		fn = __vgic_v3_write_eoir;
+		break;
 	case SYS_ICC_GRPEN1_EL1:
 		if (is_read)
 			fn = __vgic_v3_read_igrpen1;
-- 
2.11.0

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

* [PATCH v2 08/25] KVM: arm64: vgic-v3: Add ICV_EOIR1_EL1 handler
@ 2017-06-01 10:21   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

Add a handler for writing the guest's view of the ICC_EOIR1_EL1
register. This involves dropping the priority of the interrupt,
and deactivating it if required (EOImode == 0).

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/linux/irqchip/arm-gic-v3.h |   2 +
 virt/kvm/arm/hyp/vgic-v3-sr.c      | 121 +++++++++++++++++++++++++++++++++++++
 2 files changed, 123 insertions(+)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 401db585a534..e50ce5d416a3 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -417,6 +417,8 @@
 
 #define ICH_HCR_EN			(1 << 0)
 #define ICH_HCR_UIE			(1 << 1)
+#define ICH_HCR_EOIcount_SHIFT		27
+#define ICH_HCR_EOIcount_MASK		(0x1f << ICH_HCR_EOIcount_SHIFT)
 
 #define ICH_VMCR_CBPR_SHIFT		4
 #define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 16a2eadc7a5c..3f04122a5d4d 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -426,6 +426,26 @@ static int __hyp_text __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu,
 	return lr;
 }
 
+static int __hyp_text __vgic_v3_find_active_lr(struct kvm_vcpu *vcpu,
+					       int intid, u64 *lr_val)
+{
+	unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
+	int i;
+
+	for (i = 0; i < used_lrs; i++) {
+		u64 val = __gic_v3_get_lr(i);
+
+		if ((val & ICH_LR_VIRTUAL_ID_MASK) == intid &&
+		    (val & ICH_LR_ACTIVE_BIT)) {
+			*lr_val = val;
+			return i;
+		}
+	}
+
+	*lr_val = ICC_IAR1_EL1_SPURIOUS;
+	return -1;
+}
+
 static int __hyp_text __vgic_v3_get_highest_active_priority(void)
 {
 	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
@@ -506,6 +526,45 @@ static void __hyp_text __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp)
 	__vgic_v3_write_ap1rn(val | BIT(ap % 32), apr);
 }
 
+static int __hyp_text __vgic_v3_clear_highest_active_priority(void)
+{
+	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
+	u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
+	u32 hap = 0;
+	int i;
+
+	for (i = 0; i < nr_apr_regs; i++) {
+		u32 ap0, ap1;
+		int c0, c1;
+
+		ap0 = __vgic_v3_read_ap0rn(i);
+		ap1 = __vgic_v3_read_ap1rn(i);
+		if (!ap0 && !ap1) {
+			hap += 32;
+			continue;
+		}
+
+		c0 = ap0 ? __ffs(ap0) : 32;
+		c1 = ap1 ? __ffs(ap1) : 32;
+
+		/* Always clear the LSB, which is the highest priority */
+		if (c0 < c1) {
+			ap0 &= ~BIT(c0);
+			__vgic_v3_write_ap0rn(ap0, i);
+			hap += c0;
+		} else {
+			ap1 &= ~BIT(c1);
+			__vgic_v3_write_ap1rn(ap1, i);
+			hap += c1;
+		}
+
+		/* Rescale to 8 bits of priority */
+		return hap << (8 - nr_pre_bits);
+	}
+
+	return GICv3_IDLE_PRIORITY;
+}
+
 static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
 	u64 lr_val;
@@ -542,6 +601,65 @@ static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int r
 	vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS);
 }
 
+static void __hyp_text __vgic_v3_clear_active_lr(int lr, u64 lr_val)
+{
+	lr_val &= ~ICH_LR_ACTIVE_BIT;
+	if (lr_val & ICH_LR_HW) {
+		u32 pid;
+
+		pid = (lr_val & ICH_LR_PHYS_ID_MASK) >> ICH_LR_PHYS_ID_SHIFT;
+		gic_write_dir(pid);
+	}
+
+	__gic_v3_set_lr(lr_val, lr);
+}
+
+static void __hyp_text __vgic_v3_bump_eoicount(void)
+{
+	u32 hcr;
+
+	hcr = read_gicreg(ICH_HCR_EL2);
+	hcr += 1 << ICH_HCR_EOIcount_SHIFT;
+	write_gicreg(hcr, ICH_HCR_EL2);
+}
+
+static void __hyp_text __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
+{
+	u32 vid = vcpu_get_reg(vcpu, rt);
+	u64 lr_val;
+	u8 lr_prio, act_prio;
+	int lr, grp;
+
+	grp = __vgic_v3_get_group(vcpu);
+
+	/* Drop priority in any case */
+	act_prio = __vgic_v3_clear_highest_active_priority();
+
+	/* If EOIing an LPI, no deactivate to be performed */
+	if (vid >= VGIC_MIN_LPI)
+		return;
+
+	/* EOImode == 1, nothing to be done here */
+	if (vmcr & ICH_VMCR_EOIM_MASK)
+		return;
+
+	lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val);
+	if (lr == -1) {
+		__vgic_v3_bump_eoicount();
+		return;
+	}
+
+	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
+
+	/* If priorities or group do not match, the guest has fscked-up. */
+	if (grp != !!(lr_val & ICH_LR_GROUP) ||
+	    __vgic_v3_pri_to_pre(lr_prio, vmcr, grp) != act_prio)
+		return;
+
+	/* Let's now perform the deactivation */
+	__vgic_v3_clear_active_lr(lr, lr_val);
+}
+
 static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
 	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
@@ -609,6 +727,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 	case SYS_ICC_IAR1_EL1:
 		fn = __vgic_v3_read_iar;
 		break;
+	case SYS_ICC_EOIR1_EL1:
+		fn = __vgic_v3_write_eoir;
+		break;
 	case SYS_ICC_GRPEN1_EL1:
 		if (is_read)
 			fn = __vgic_v3_read_igrpen1;
-- 
2.11.0

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

* [PATCH v2 09/25] KVM: arm64: vgic-v3: Add ICV_AP1Rn_EL1 handler
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:21   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter, kvmarm,
	linux-arm-kernel

Add a handler for reading/writing the guest's view of the ICV_AP1Rn_EL1
registers. We just map them to the corresponding ICH_AP1Rn_EL2 registers.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/sysreg.h |  1 +
 virt/kvm/arm/hyp/vgic-v3-sr.c   | 94 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 95 insertions(+)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 15c142ce991c..aad46b8eea5e 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -180,6 +180,7 @@
 
 #define SYS_VBAR_EL1			sys_reg(3, 0, 12, 0, 0)
 
+#define SYS_ICC_AP1Rn_EL1(n)		sys_reg(3, 0, 12, 9, n)
 #define SYS_ICC_DIR_EL1			sys_reg(3, 0, 12, 11, 1)
 #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
 #define SYS_ICC_IAR1_EL1		sys_reg(3, 0, 12, 12, 0)
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 3f04122a5d4d..d4f07f84602d 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -702,6 +702,76 @@ static void __hyp_text __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int
 	__vgic_v3_write_vmcr(vmcr);
 }
 
+static void __hyp_text __vgic_v3_read_apxrn(struct kvm_vcpu *vcpu, int rt, int n)
+{
+	u32 val;
+
+	if (!__vgic_v3_get_group(vcpu))
+		val = __vgic_v3_read_ap0rn(n);
+	else
+		val = __vgic_v3_read_ap1rn(n);
+
+	vcpu_set_reg(vcpu, rt, val);
+}
+
+static void __hyp_text __vgic_v3_write_apxrn(struct kvm_vcpu *vcpu, int rt, int n)
+{
+	u32 val = vcpu_get_reg(vcpu, rt);
+
+	if (!__vgic_v3_get_group(vcpu))
+		__vgic_v3_write_ap0rn(val, n);
+	else
+		__vgic_v3_write_ap1rn(val, n);
+}
+
+static void __hyp_text __vgic_v3_read_apxr0(struct kvm_vcpu *vcpu,
+					    u32 vmcr, int rt)
+{
+	__vgic_v3_read_apxrn(vcpu, rt, 0);
+}
+
+static void __hyp_text __vgic_v3_read_apxr1(struct kvm_vcpu *vcpu,
+					    u32 vmcr, int rt)
+{
+	__vgic_v3_read_apxrn(vcpu, rt, 1);
+}
+
+static void __hyp_text __vgic_v3_read_apxr2(struct kvm_vcpu *vcpu,
+					    u32 vmcr, int rt)
+{
+	__vgic_v3_read_apxrn(vcpu, rt, 2);
+}
+
+static void __hyp_text __vgic_v3_read_apxr3(struct kvm_vcpu *vcpu,
+					    u32 vmcr, int rt)
+{
+	__vgic_v3_read_apxrn(vcpu, rt, 3);
+}
+
+static void __hyp_text __vgic_v3_write_apxr0(struct kvm_vcpu *vcpu,
+					     u32 vmcr, int rt)
+{
+	__vgic_v3_write_apxrn(vcpu, rt, 0);
+}
+
+static void __hyp_text __vgic_v3_write_apxr1(struct kvm_vcpu *vcpu,
+					     u32 vmcr, int rt)
+{
+	__vgic_v3_write_apxrn(vcpu, rt, 1);
+}
+
+static void __hyp_text __vgic_v3_write_apxr2(struct kvm_vcpu *vcpu,
+					     u32 vmcr, int rt)
+{
+	__vgic_v3_write_apxrn(vcpu, rt, 2);
+}
+
+static void __hyp_text __vgic_v3_write_apxr3(struct kvm_vcpu *vcpu,
+					     u32 vmcr, int rt)
+{
+	__vgic_v3_write_apxrn(vcpu, rt, 3);
+}
+
 int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 {
 	int rt;
@@ -742,6 +812,30 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 		else
 			fn = __vgic_v3_write_bpr1;
 		break;
+	case SYS_ICC_AP1Rn_EL1(0):
+		if (is_read)
+			fn = __vgic_v3_read_apxr0;
+		else
+			fn = __vgic_v3_write_apxr0;
+		break;
+	case SYS_ICC_AP1Rn_EL1(1):
+		if (is_read)
+			fn = __vgic_v3_read_apxr1;
+		else
+			fn = __vgic_v3_write_apxr1;
+		break;
+	case SYS_ICC_AP1Rn_EL1(2):
+		if (is_read)
+			fn = __vgic_v3_read_apxr2;
+		else
+			fn = __vgic_v3_write_apxr2;
+		break;
+	case SYS_ICC_AP1Rn_EL1(3):
+		if (is_read)
+			fn = __vgic_v3_read_apxr3;
+		else
+			fn = __vgic_v3_write_apxr3;
+		break;
 	default:
 		return 0;
 	}
-- 
2.11.0

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

* [PATCH v2 09/25] KVM: arm64: vgic-v3: Add ICV_AP1Rn_EL1 handler
@ 2017-06-01 10:21   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

Add a handler for reading/writing the guest's view of the ICV_AP1Rn_EL1
registers. We just map them to the corresponding ICH_AP1Rn_EL2 registers.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/sysreg.h |  1 +
 virt/kvm/arm/hyp/vgic-v3-sr.c   | 94 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 95 insertions(+)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 15c142ce991c..aad46b8eea5e 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -180,6 +180,7 @@
 
 #define SYS_VBAR_EL1			sys_reg(3, 0, 12, 0, 0)
 
+#define SYS_ICC_AP1Rn_EL1(n)		sys_reg(3, 0, 12, 9, n)
 #define SYS_ICC_DIR_EL1			sys_reg(3, 0, 12, 11, 1)
 #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
 #define SYS_ICC_IAR1_EL1		sys_reg(3, 0, 12, 12, 0)
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 3f04122a5d4d..d4f07f84602d 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -702,6 +702,76 @@ static void __hyp_text __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int
 	__vgic_v3_write_vmcr(vmcr);
 }
 
+static void __hyp_text __vgic_v3_read_apxrn(struct kvm_vcpu *vcpu, int rt, int n)
+{
+	u32 val;
+
+	if (!__vgic_v3_get_group(vcpu))
+		val = __vgic_v3_read_ap0rn(n);
+	else
+		val = __vgic_v3_read_ap1rn(n);
+
+	vcpu_set_reg(vcpu, rt, val);
+}
+
+static void __hyp_text __vgic_v3_write_apxrn(struct kvm_vcpu *vcpu, int rt, int n)
+{
+	u32 val = vcpu_get_reg(vcpu, rt);
+
+	if (!__vgic_v3_get_group(vcpu))
+		__vgic_v3_write_ap0rn(val, n);
+	else
+		__vgic_v3_write_ap1rn(val, n);
+}
+
+static void __hyp_text __vgic_v3_read_apxr0(struct kvm_vcpu *vcpu,
+					    u32 vmcr, int rt)
+{
+	__vgic_v3_read_apxrn(vcpu, rt, 0);
+}
+
+static void __hyp_text __vgic_v3_read_apxr1(struct kvm_vcpu *vcpu,
+					    u32 vmcr, int rt)
+{
+	__vgic_v3_read_apxrn(vcpu, rt, 1);
+}
+
+static void __hyp_text __vgic_v3_read_apxr2(struct kvm_vcpu *vcpu,
+					    u32 vmcr, int rt)
+{
+	__vgic_v3_read_apxrn(vcpu, rt, 2);
+}
+
+static void __hyp_text __vgic_v3_read_apxr3(struct kvm_vcpu *vcpu,
+					    u32 vmcr, int rt)
+{
+	__vgic_v3_read_apxrn(vcpu, rt, 3);
+}
+
+static void __hyp_text __vgic_v3_write_apxr0(struct kvm_vcpu *vcpu,
+					     u32 vmcr, int rt)
+{
+	__vgic_v3_write_apxrn(vcpu, rt, 0);
+}
+
+static void __hyp_text __vgic_v3_write_apxr1(struct kvm_vcpu *vcpu,
+					     u32 vmcr, int rt)
+{
+	__vgic_v3_write_apxrn(vcpu, rt, 1);
+}
+
+static void __hyp_text __vgic_v3_write_apxr2(struct kvm_vcpu *vcpu,
+					     u32 vmcr, int rt)
+{
+	__vgic_v3_write_apxrn(vcpu, rt, 2);
+}
+
+static void __hyp_text __vgic_v3_write_apxr3(struct kvm_vcpu *vcpu,
+					     u32 vmcr, int rt)
+{
+	__vgic_v3_write_apxrn(vcpu, rt, 3);
+}
+
 int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 {
 	int rt;
@@ -742,6 +812,30 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 		else
 			fn = __vgic_v3_write_bpr1;
 		break;
+	case SYS_ICC_AP1Rn_EL1(0):
+		if (is_read)
+			fn = __vgic_v3_read_apxr0;
+		else
+			fn = __vgic_v3_write_apxr0;
+		break;
+	case SYS_ICC_AP1Rn_EL1(1):
+		if (is_read)
+			fn = __vgic_v3_read_apxr1;
+		else
+			fn = __vgic_v3_write_apxr1;
+		break;
+	case SYS_ICC_AP1Rn_EL1(2):
+		if (is_read)
+			fn = __vgic_v3_read_apxr2;
+		else
+			fn = __vgic_v3_write_apxr2;
+		break;
+	case SYS_ICC_AP1Rn_EL1(3):
+		if (is_read)
+			fn = __vgic_v3_read_apxr3;
+		else
+			fn = __vgic_v3_write_apxr3;
+		break;
 	default:
 		return 0;
 	}
-- 
2.11.0

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

* [PATCH v2 10/25] KVM: arm64: vgic-v3: Add ICV_HPPIR1_EL1 handler
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:21   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: David Daney, Catalin Marinas, Mark Rutland, Robert Richter,
	Eric Auger, kvmarm, linux-arm-kernel, kvm

Add a handler for reading the guest's view of the ICV_HPPIR1_EL1
register. This is a simple parsing of the available LRs, extracting the
highest available interrupt.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/sysreg.h |  1 +
 virt/kvm/arm/hyp/vgic-v3-sr.c   | 23 +++++++++++++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index aad46b8eea5e..bd000686194a 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -185,6 +185,7 @@
 #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
 #define SYS_ICC_IAR1_EL1		sys_reg(3, 0, 12, 12, 0)
 #define SYS_ICC_EOIR1_EL1		sys_reg(3, 0, 12, 12, 1)
+#define SYS_ICC_HPPIR1_EL1		sys_reg(3, 0, 12, 12, 2)
 #define SYS_ICC_BPR1_EL1		sys_reg(3, 0, 12, 12, 3)
 #define SYS_ICC_CTLR_EL1		sys_reg(3, 0, 12, 12, 4)
 #define SYS_ICC_SRE_EL1			sys_reg(3, 0, 12, 12, 5)
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index d4f07f84602d..f0bc711db258 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -772,6 +772,26 @@ static void __hyp_text __vgic_v3_write_apxr3(struct kvm_vcpu *vcpu,
 	__vgic_v3_write_apxrn(vcpu, rt, 3);
 }
 
+static void __hyp_text __vgic_v3_read_hppir(struct kvm_vcpu *vcpu,
+					    u32 vmcr, int rt)
+{
+	u64 lr_val;
+	int lr, lr_grp, grp;
+
+	grp = __vgic_v3_get_group(vcpu);
+
+	lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
+	if (lr == -1)
+		goto spurious;
+
+	lr_grp = !!(lr_val & ICH_LR_GROUP);
+	if (lr_grp != grp)
+		lr_val = ICC_IAR1_EL1_SPURIOUS;
+
+spurious:
+	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
+}
+
 int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 {
 	int rt;
@@ -836,6 +856,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 		else
 			fn = __vgic_v3_write_apxr3;
 		break;
+	case SYS_ICC_HPPIR1_EL1:
+		fn = __vgic_v3_read_hppir;
+		break;
 	default:
 		return 0;
 	}
-- 
2.11.0

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

* [PATCH v2 10/25] KVM: arm64: vgic-v3: Add ICV_HPPIR1_EL1 handler
@ 2017-06-01 10:21   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

Add a handler for reading the guest's view of the ICV_HPPIR1_EL1
register. This is a simple parsing of the available LRs, extracting the
highest available interrupt.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/sysreg.h |  1 +
 virt/kvm/arm/hyp/vgic-v3-sr.c   | 23 +++++++++++++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index aad46b8eea5e..bd000686194a 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -185,6 +185,7 @@
 #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
 #define SYS_ICC_IAR1_EL1		sys_reg(3, 0, 12, 12, 0)
 #define SYS_ICC_EOIR1_EL1		sys_reg(3, 0, 12, 12, 1)
+#define SYS_ICC_HPPIR1_EL1		sys_reg(3, 0, 12, 12, 2)
 #define SYS_ICC_BPR1_EL1		sys_reg(3, 0, 12, 12, 3)
 #define SYS_ICC_CTLR_EL1		sys_reg(3, 0, 12, 12, 4)
 #define SYS_ICC_SRE_EL1			sys_reg(3, 0, 12, 12, 5)
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index d4f07f84602d..f0bc711db258 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -772,6 +772,26 @@ static void __hyp_text __vgic_v3_write_apxr3(struct kvm_vcpu *vcpu,
 	__vgic_v3_write_apxrn(vcpu, rt, 3);
 }
 
+static void __hyp_text __vgic_v3_read_hppir(struct kvm_vcpu *vcpu,
+					    u32 vmcr, int rt)
+{
+	u64 lr_val;
+	int lr, lr_grp, grp;
+
+	grp = __vgic_v3_get_group(vcpu);
+
+	lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
+	if (lr == -1)
+		goto spurious;
+
+	lr_grp = !!(lr_val & ICH_LR_GROUP);
+	if (lr_grp != grp)
+		lr_val = ICC_IAR1_EL1_SPURIOUS;
+
+spurious:
+	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
+}
+
 int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 {
 	int rt;
@@ -836,6 +856,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 		else
 			fn = __vgic_v3_write_apxr3;
 		break;
+	case SYS_ICC_HPPIR1_EL1:
+		fn = __vgic_v3_read_hppir;
+		break;
 	default:
 		return 0;
 	}
-- 
2.11.0

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

* [PATCH v2 11/25] KVM: arm64: vgic-v3: Enable trapping of Group-1 system registers
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:21   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: David Daney, Catalin Marinas, Mark Rutland, Robert Richter,
	Eric Auger, kvmarm, linux-arm-kernel, kvm

In order to be able to trap Group-1 GICv3 system registers, we need to
set ICH_HCR_EL2.TALL1 before entering the guest. This is conditionally
done after having restored the guest's state, and cleared on exit.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/linux/irqchip/arm-gic-v3.h | 1 +
 virt/kvm/arm/hyp/vgic-v3-sr.c      | 7 +++++++
 virt/kvm/arm/vgic/vgic-v3.c        | 4 ++++
 3 files changed, 12 insertions(+)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index e50ce5d416a3..03b5a28bb2d0 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -417,6 +417,7 @@
 
 #define ICH_HCR_EN			(1 << 0)
 #define ICH_HCR_UIE			(1 << 1)
+#define ICH_HCR_TALL1			(1 << 12)
 #define ICH_HCR_EOIcount_SHIFT		27
 #define ICH_HCR_EOIcount_MASK		(0x1f << ICH_HCR_EOIcount_SHIFT)
 
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index f0bc711db258..8973bad35748 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -258,6 +258,9 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 			cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0);
 		}
 	} else {
+		if (static_branch_unlikely(&vgic_v3_cpuif_trap))
+			write_gicreg(0, ICH_HCR_EL2);
+
 		cpu_if->vgic_elrsr = 0xffff;
 		cpu_if->vgic_ap0r[0] = 0;
 		cpu_if->vgic_ap0r[1] = 0;
@@ -330,6 +333,10 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 
 		for (i = 0; i < used_lrs; i++)
 			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
+	} else {
+		/* Always write ICH_HCR_EL2 to enable trapping */
+		if (static_branch_unlikely(&vgic_v3_cpuif_trap))
+			write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
 	}
 
 	/*
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 88d9bd9bf468..fbd678bc046d 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -21,6 +21,8 @@
 
 #include "vgic.h"
 
+static bool group1_trap;
+
 void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
@@ -239,6 +241,8 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
 
 	/* Get the show on the road... */
 	vgic_v3->vgic_hcr = ICH_HCR_EN;
+	if (group1_trap)
+		vgic_v3->vgic_hcr |= ICH_HCR_TALL1;
 }
 
 int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq)
-- 
2.11.0

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

* [PATCH v2 11/25] KVM: arm64: vgic-v3: Enable trapping of Group-1 system registers
@ 2017-06-01 10:21   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

In order to be able to trap Group-1 GICv3 system registers, we need to
set ICH_HCR_EL2.TALL1 before entering the guest. This is conditionally
done after having restored the guest's state, and cleared on exit.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/linux/irqchip/arm-gic-v3.h | 1 +
 virt/kvm/arm/hyp/vgic-v3-sr.c      | 7 +++++++
 virt/kvm/arm/vgic/vgic-v3.c        | 4 ++++
 3 files changed, 12 insertions(+)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index e50ce5d416a3..03b5a28bb2d0 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -417,6 +417,7 @@
 
 #define ICH_HCR_EN			(1 << 0)
 #define ICH_HCR_UIE			(1 << 1)
+#define ICH_HCR_TALL1			(1 << 12)
 #define ICH_HCR_EOIcount_SHIFT		27
 #define ICH_HCR_EOIcount_MASK		(0x1f << ICH_HCR_EOIcount_SHIFT)
 
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index f0bc711db258..8973bad35748 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -258,6 +258,9 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 			cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0);
 		}
 	} else {
+		if (static_branch_unlikely(&vgic_v3_cpuif_trap))
+			write_gicreg(0, ICH_HCR_EL2);
+
 		cpu_if->vgic_elrsr = 0xffff;
 		cpu_if->vgic_ap0r[0] = 0;
 		cpu_if->vgic_ap0r[1] = 0;
@@ -330,6 +333,10 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 
 		for (i = 0; i < used_lrs; i++)
 			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
+	} else {
+		/* Always write ICH_HCR_EL2 to enable trapping */
+		if (static_branch_unlikely(&vgic_v3_cpuif_trap))
+			write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
 	}
 
 	/*
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 88d9bd9bf468..fbd678bc046d 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -21,6 +21,8 @@
 
 #include "vgic.h"
 
+static bool group1_trap;
+
 void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
 {
 	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
@@ -239,6 +241,8 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
 
 	/* Get the show on the road... */
 	vgic_v3->vgic_hcr = ICH_HCR_EN;
+	if (group1_trap)
+		vgic_v3->vgic_hcr |= ICH_HCR_TALL1;
 }
 
 int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq)
-- 
2.11.0

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

* [PATCH v2 12/25] KVM: arm64: Enable GICv3 Group-1 sysreg trapping via command-line
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:21   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter, kvmarm,
	linux-arm-kernel

Now that we're able to safely handle Group-1 sysreg access, let's
give the user the opportunity to enable it by passing a specific
command-line option (vgic_v3.group1_trap).

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/hyp/vgic-v3-sr.c |  6 +++++-
 virt/kvm/arm/vgic/vgic-v3.c   | 11 +++++++++++
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 8973bad35748..42ac9ee7650a 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -334,7 +334,11 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 		for (i = 0; i < used_lrs; i++)
 			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
 	} else {
-		/* Always write ICH_HCR_EL2 to enable trapping */
+		/*
+                 * If we don't have any interrupt to inject, but that
+		 * trapping is enabled, write the ICH_HCR_EL2 config
+		 * anyway.
+		 */
 		if (static_branch_unlikely(&vgic_v3_cpuif_trap))
 			write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
 	}
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index fbd678bc046d..a16769276efd 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -416,6 +416,12 @@ int vgic_v3_map_resources(struct kvm *kvm)
 
 DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap);
 
+static int __init early_group1_trap_cfg(char *buf)
+{
+	return strtobool(buf, &group1_trap);
+}
+early_param("vgic_v3.group1_trap", early_group1_trap_cfg);
+
 /**
  * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
  * @node:	pointer to the DT node
@@ -467,6 +473,11 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
 	if (kvm_vgic_global_state.vcpu_base == 0)
 		kvm_info("disabling GICv2 emulation\n");
 
+	if (group1_trap) {
+		kvm_info("GICv3 sysreg trapping enabled (reduced performance)\n");
+		static_branch_enable(&vgic_v3_cpuif_trap);
+	}
+
 	kvm_vgic_global_state.vctrl_base = NULL;
 	kvm_vgic_global_state.type = VGIC_V3;
 	kvm_vgic_global_state.max_gic_vcpus = VGIC_V3_MAX_CPUS;
-- 
2.11.0

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

* [PATCH v2 12/25] KVM: arm64: Enable GICv3 Group-1 sysreg trapping via command-line
@ 2017-06-01 10:21   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

Now that we're able to safely handle Group-1 sysreg access, let's
give the user the opportunity to enable it by passing a specific
command-line option (vgic_v3.group1_trap).

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/hyp/vgic-v3-sr.c |  6 +++++-
 virt/kvm/arm/vgic/vgic-v3.c   | 11 +++++++++++
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 8973bad35748..42ac9ee7650a 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -334,7 +334,11 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
 		for (i = 0; i < used_lrs; i++)
 			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
 	} else {
-		/* Always write ICH_HCR_EL2 to enable trapping */
+		/*
+                 * If we don't have any interrupt to inject, but that
+		 * trapping is enabled, write the ICH_HCR_EL2 config
+		 * anyway.
+		 */
 		if (static_branch_unlikely(&vgic_v3_cpuif_trap))
 			write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
 	}
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index fbd678bc046d..a16769276efd 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -416,6 +416,12 @@ int vgic_v3_map_resources(struct kvm *kvm)
 
 DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap);
 
+static int __init early_group1_trap_cfg(char *buf)
+{
+	return strtobool(buf, &group1_trap);
+}
+early_param("vgic_v3.group1_trap", early_group1_trap_cfg);
+
 /**
  * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
  * @node:	pointer to the DT node
@@ -467,6 +473,11 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
 	if (kvm_vgic_global_state.vcpu_base == 0)
 		kvm_info("disabling GICv2 emulation\n");
 
+	if (group1_trap) {
+		kvm_info("GICv3 sysreg trapping enabled (reduced performance)\n");
+		static_branch_enable(&vgic_v3_cpuif_trap);
+	}
+
 	kvm_vgic_global_state.vctrl_base = NULL;
 	kvm_vgic_global_state.type = VGIC_V3;
 	kvm_vgic_global_state.max_gic_vcpus = VGIC_V3_MAX_CPUS;
-- 
2.11.0

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

* [PATCH v2 13/25] KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:21   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter, kvmarm,
	linux-arm-kernel

Add a handler for reading/writing the guest's view of the ICC_BPR0_EL1
register, which is located in the ICH_VMCR_EL2.BPR0 field.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/sysreg.h |  1 +
 virt/kvm/arm/hyp/vgic-v3-sr.c   | 36 ++++++++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index bd000686194a..d20be0b28ca4 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -180,6 +180,7 @@
 
 #define SYS_VBAR_EL1			sys_reg(3, 0, 12, 0, 0)
 
+#define SYS_ICC_BPR0_EL1		sys_reg(3, 0, 12, 8, 3)
 #define SYS_ICC_AP1Rn_EL1(n)		sys_reg(3, 0, 12, 9, n)
 #define SYS_ICC_DIR_EL1			sys_reg(3, 0, 12, 11, 1)
 #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 42ac9ee7650a..54a8e828c85b 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -688,11 +688,41 @@ static void __hyp_text __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr,
 	__vgic_v3_write_vmcr(vmcr);
 }
 
+static void __hyp_text __vgic_v3_read_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
+{
+	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr0(vmcr));
+}
+
 static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
 	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
 }
 
+static void __hyp_text __vgic_v3_write_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
+{
+	u64 val = vcpu_get_reg(vcpu, rt);
+	u8 bpr_min = 7 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
+
+	/* Enforce BPR limiting */
+	if (val < bpr_min)
+		val = bpr_min;
+
+	val <<= ICH_VMCR_BPR0_SHIFT;
+	val &= ICH_VMCR_BPR0_MASK;
+	vmcr &= ~ICH_VMCR_BPR0_MASK;
+	vmcr |= val;
+
+	if (vmcr & ICH_VMCR_CBPR_MASK) {
+		val = __vgic_v3_get_bpr1(vmcr);
+		val <<= ICH_VMCR_BPR1_SHIFT;
+		val &= ICH_VMCR_BPR1_MASK;
+		vmcr &= ~ICH_VMCR_BPR1_MASK;
+		vmcr |= val;
+	}
+
+	__vgic_v3_write_vmcr(vmcr);
+}
+
 static void __hyp_text __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
 	u64 val = vcpu_get_reg(vcpu, rt);
@@ -870,6 +900,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 	case SYS_ICC_HPPIR1_EL1:
 		fn = __vgic_v3_read_hppir;
 		break;
+	case SYS_ICC_BPR0_EL1:
+		if (is_read)
+			fn = __vgic_v3_read_bpr0;
+		else
+			fn = __vgic_v3_write_bpr0;
+		break;
 	default:
 		return 0;
 	}
-- 
2.11.0

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

* [PATCH v2 13/25] KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler
@ 2017-06-01 10:21   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

Add a handler for reading/writing the guest's view of the ICC_BPR0_EL1
register, which is located in the ICH_VMCR_EL2.BPR0 field.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/sysreg.h |  1 +
 virt/kvm/arm/hyp/vgic-v3-sr.c   | 36 ++++++++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index bd000686194a..d20be0b28ca4 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -180,6 +180,7 @@
 
 #define SYS_VBAR_EL1			sys_reg(3, 0, 12, 0, 0)
 
+#define SYS_ICC_BPR0_EL1		sys_reg(3, 0, 12, 8, 3)
 #define SYS_ICC_AP1Rn_EL1(n)		sys_reg(3, 0, 12, 9, n)
 #define SYS_ICC_DIR_EL1			sys_reg(3, 0, 12, 11, 1)
 #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 42ac9ee7650a..54a8e828c85b 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -688,11 +688,41 @@ static void __hyp_text __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr,
 	__vgic_v3_write_vmcr(vmcr);
 }
 
+static void __hyp_text __vgic_v3_read_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
+{
+	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr0(vmcr));
+}
+
 static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
 	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
 }
 
+static void __hyp_text __vgic_v3_write_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
+{
+	u64 val = vcpu_get_reg(vcpu, rt);
+	u8 bpr_min = 7 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
+
+	/* Enforce BPR limiting */
+	if (val < bpr_min)
+		val = bpr_min;
+
+	val <<= ICH_VMCR_BPR0_SHIFT;
+	val &= ICH_VMCR_BPR0_MASK;
+	vmcr &= ~ICH_VMCR_BPR0_MASK;
+	vmcr |= val;
+
+	if (vmcr & ICH_VMCR_CBPR_MASK) {
+		val = __vgic_v3_get_bpr1(vmcr);
+		val <<= ICH_VMCR_BPR1_SHIFT;
+		val &= ICH_VMCR_BPR1_MASK;
+		vmcr &= ~ICH_VMCR_BPR1_MASK;
+		vmcr |= val;
+	}
+
+	__vgic_v3_write_vmcr(vmcr);
+}
+
 static void __hyp_text __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
 	u64 val = vcpu_get_reg(vcpu, rt);
@@ -870,6 +900,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 	case SYS_ICC_HPPIR1_EL1:
 		fn = __vgic_v3_read_hppir;
 		break;
+	case SYS_ICC_BPR0_EL1:
+		if (is_read)
+			fn = __vgic_v3_read_bpr0;
+		else
+			fn = __vgic_v3_write_bpr0;
+		break;
 	default:
 		return 0;
 	}
-- 
2.11.0

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

* [PATCH v2 14/25] KVM: arm64: vgic-v3: Add ICV_IGNREN0_EL1 handler
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:21   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter, kvmarm,
	linux-arm-kernel

Add a handler for reading/writing the guest's view of the ICC_IGRPEN0_EL1
register, which is located in the ICH_VMCR_EL2.VENG0 field.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/sysreg.h |  1 +
 virt/kvm/arm/hyp/vgic-v3-sr.c   | 23 +++++++++++++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index d20be0b28ca4..ba93bc7ac8e4 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -190,6 +190,7 @@
 #define SYS_ICC_BPR1_EL1		sys_reg(3, 0, 12, 12, 3)
 #define SYS_ICC_CTLR_EL1		sys_reg(3, 0, 12, 12, 4)
 #define SYS_ICC_SRE_EL1			sys_reg(3, 0, 12, 12, 5)
+#define SYS_ICC_GRPEN0_EL1		sys_reg(3, 0, 12, 12, 6)
 #define SYS_ICC_GRPEN1_EL1		sys_reg(3, 0, 12, 12, 7)
 
 #define SYS_CONTEXTIDR_EL1		sys_reg(3, 0, 13, 0, 1)
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 54a8e828c85b..b1b9129da045 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -671,11 +671,28 @@ static void __hyp_text __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int
 	__vgic_v3_clear_active_lr(lr, lr_val);
 }
 
+static void __hyp_text __vgic_v3_read_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
+{
+	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG0_MASK));
+}
+
 static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
 	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
 }
 
+static void __hyp_text __vgic_v3_write_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
+{
+	u64 val = vcpu_get_reg(vcpu, rt);
+
+	if (val & 1)
+		vmcr |= ICH_VMCR_ENG0_MASK;
+	else
+		vmcr &= ~ICH_VMCR_ENG0_MASK;
+
+	__vgic_v3_write_vmcr(vmcr);
+}
+
 static void __hyp_text __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
 	u64 val = vcpu_get_reg(vcpu, rt);
@@ -900,6 +917,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 	case SYS_ICC_HPPIR1_EL1:
 		fn = __vgic_v3_read_hppir;
 		break;
+	case SYS_ICC_GRPEN0_EL1:
+		if (is_read)
+			fn = __vgic_v3_read_igrpen0;
+		else
+			fn = __vgic_v3_write_igrpen0;
+		break;
 	case SYS_ICC_BPR0_EL1:
 		if (is_read)
 			fn = __vgic_v3_read_bpr0;
-- 
2.11.0

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

* [PATCH v2 14/25] KVM: arm64: vgic-v3: Add ICV_IGNREN0_EL1 handler
@ 2017-06-01 10:21   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

Add a handler for reading/writing the guest's view of the ICC_IGRPEN0_EL1
register, which is located in the ICH_VMCR_EL2.VENG0 field.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/sysreg.h |  1 +
 virt/kvm/arm/hyp/vgic-v3-sr.c   | 23 +++++++++++++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index d20be0b28ca4..ba93bc7ac8e4 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -190,6 +190,7 @@
 #define SYS_ICC_BPR1_EL1		sys_reg(3, 0, 12, 12, 3)
 #define SYS_ICC_CTLR_EL1		sys_reg(3, 0, 12, 12, 4)
 #define SYS_ICC_SRE_EL1			sys_reg(3, 0, 12, 12, 5)
+#define SYS_ICC_GRPEN0_EL1		sys_reg(3, 0, 12, 12, 6)
 #define SYS_ICC_GRPEN1_EL1		sys_reg(3, 0, 12, 12, 7)
 
 #define SYS_CONTEXTIDR_EL1		sys_reg(3, 0, 13, 0, 1)
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 54a8e828c85b..b1b9129da045 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -671,11 +671,28 @@ static void __hyp_text __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int
 	__vgic_v3_clear_active_lr(lr, lr_val);
 }
 
+static void __hyp_text __vgic_v3_read_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
+{
+	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG0_MASK));
+}
+
 static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
 	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
 }
 
+static void __hyp_text __vgic_v3_write_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
+{
+	u64 val = vcpu_get_reg(vcpu, rt);
+
+	if (val & 1)
+		vmcr |= ICH_VMCR_ENG0_MASK;
+	else
+		vmcr &= ~ICH_VMCR_ENG0_MASK;
+
+	__vgic_v3_write_vmcr(vmcr);
+}
+
 static void __hyp_text __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
 	u64 val = vcpu_get_reg(vcpu, rt);
@@ -900,6 +917,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 	case SYS_ICC_HPPIR1_EL1:
 		fn = __vgic_v3_read_hppir;
 		break;
+	case SYS_ICC_GRPEN0_EL1:
+		if (is_read)
+			fn = __vgic_v3_read_igrpen0;
+		else
+			fn = __vgic_v3_write_igrpen0;
+		break;
 	case SYS_ICC_BPR0_EL1:
 		if (is_read)
 			fn = __vgic_v3_read_bpr0;
-- 
2.11.0

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

* [PATCH v2 15/25] KVM: arm64: vgic-v3: Add misc Group-0 handlers
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:21   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter, kvmarm,
	linux-arm-kernel

A number of Group-0 registers can be handled by the same accessors
as that of Group-1, so let's add the required system register encodings
and catch them in the dispatching function.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/sysreg.h | 4 ++++
 virt/kvm/arm/hyp/vgic-v3-sr.c   | 7 +++++++
 2 files changed, 11 insertions(+)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index ba93bc7ac8e4..9971c5c435a7 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -180,7 +180,11 @@
 
 #define SYS_VBAR_EL1			sys_reg(3, 0, 12, 0, 0)
 
+#define SYS_ICC_IAR0_EL1		sys_reg(3, 0, 12, 8, 0)
+#define SYS_ICC_EOIR0_EL1		sys_reg(3, 0, 12, 8, 1)
+#define SYS_ICC_HPPIR0_EL1		sys_reg(3, 0, 12, 8, 2)
 #define SYS_ICC_BPR0_EL1		sys_reg(3, 0, 12, 8, 3)
+#define SYS_ICC_AP0Rn_EL1(n)		sys_reg(3, 0, 12, 8, 4 | n)
 #define SYS_ICC_AP1Rn_EL1(n)		sys_reg(3, 0, 12, 9, n)
 #define SYS_ICC_DIR_EL1			sys_reg(3, 0, 12, 11, 1)
 #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index b1b9129da045..5ff788d308ee 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -872,9 +872,11 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
 
 	switch (sysreg) {
+	case SYS_ICC_IAR0_EL1:
 	case SYS_ICC_IAR1_EL1:
 		fn = __vgic_v3_read_iar;
 		break;
+	case SYS_ICC_EOIR0_EL1:
 	case SYS_ICC_EOIR1_EL1:
 		fn = __vgic_v3_write_eoir;
 		break;
@@ -890,30 +892,35 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 		else
 			fn = __vgic_v3_write_bpr1;
 		break;
+	case SYS_ICC_AP0Rn_EL1(0):
 	case SYS_ICC_AP1Rn_EL1(0):
 		if (is_read)
 			fn = __vgic_v3_read_apxr0;
 		else
 			fn = __vgic_v3_write_apxr0;
 		break;
+	case SYS_ICC_AP0Rn_EL1(1):
 	case SYS_ICC_AP1Rn_EL1(1):
 		if (is_read)
 			fn = __vgic_v3_read_apxr1;
 		else
 			fn = __vgic_v3_write_apxr1;
 		break;
+	case SYS_ICC_AP0Rn_EL1(2):
 	case SYS_ICC_AP1Rn_EL1(2):
 		if (is_read)
 			fn = __vgic_v3_read_apxr2;
 		else
 			fn = __vgic_v3_write_apxr2;
 		break;
+	case SYS_ICC_AP0Rn_EL1(3):
 	case SYS_ICC_AP1Rn_EL1(3):
 		if (is_read)
 			fn = __vgic_v3_read_apxr3;
 		else
 			fn = __vgic_v3_write_apxr3;
 		break;
+	case SYS_ICC_HPPIR0_EL1:
 	case SYS_ICC_HPPIR1_EL1:
 		fn = __vgic_v3_read_hppir;
 		break;
-- 
2.11.0

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

* [PATCH v2 15/25] KVM: arm64: vgic-v3: Add misc Group-0 handlers
@ 2017-06-01 10:21   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

A number of Group-0 registers can be handled by the same accessors
as that of Group-1, so let's add the required system register encodings
and catch them in the dispatching function.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/sysreg.h | 4 ++++
 virt/kvm/arm/hyp/vgic-v3-sr.c   | 7 +++++++
 2 files changed, 11 insertions(+)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index ba93bc7ac8e4..9971c5c435a7 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -180,7 +180,11 @@
 
 #define SYS_VBAR_EL1			sys_reg(3, 0, 12, 0, 0)
 
+#define SYS_ICC_IAR0_EL1		sys_reg(3, 0, 12, 8, 0)
+#define SYS_ICC_EOIR0_EL1		sys_reg(3, 0, 12, 8, 1)
+#define SYS_ICC_HPPIR0_EL1		sys_reg(3, 0, 12, 8, 2)
 #define SYS_ICC_BPR0_EL1		sys_reg(3, 0, 12, 8, 3)
+#define SYS_ICC_AP0Rn_EL1(n)		sys_reg(3, 0, 12, 8, 4 | n)
 #define SYS_ICC_AP1Rn_EL1(n)		sys_reg(3, 0, 12, 9, n)
 #define SYS_ICC_DIR_EL1			sys_reg(3, 0, 12, 11, 1)
 #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index b1b9129da045..5ff788d308ee 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -872,9 +872,11 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
 
 	switch (sysreg) {
+	case SYS_ICC_IAR0_EL1:
 	case SYS_ICC_IAR1_EL1:
 		fn = __vgic_v3_read_iar;
 		break;
+	case SYS_ICC_EOIR0_EL1:
 	case SYS_ICC_EOIR1_EL1:
 		fn = __vgic_v3_write_eoir;
 		break;
@@ -890,30 +892,35 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 		else
 			fn = __vgic_v3_write_bpr1;
 		break;
+	case SYS_ICC_AP0Rn_EL1(0):
 	case SYS_ICC_AP1Rn_EL1(0):
 		if (is_read)
 			fn = __vgic_v3_read_apxr0;
 		else
 			fn = __vgic_v3_write_apxr0;
 		break;
+	case SYS_ICC_AP0Rn_EL1(1):
 	case SYS_ICC_AP1Rn_EL1(1):
 		if (is_read)
 			fn = __vgic_v3_read_apxr1;
 		else
 			fn = __vgic_v3_write_apxr1;
 		break;
+	case SYS_ICC_AP0Rn_EL1(2):
 	case SYS_ICC_AP1Rn_EL1(2):
 		if (is_read)
 			fn = __vgic_v3_read_apxr2;
 		else
 			fn = __vgic_v3_write_apxr2;
 		break;
+	case SYS_ICC_AP0Rn_EL1(3):
 	case SYS_ICC_AP1Rn_EL1(3):
 		if (is_read)
 			fn = __vgic_v3_read_apxr3;
 		else
 			fn = __vgic_v3_write_apxr3;
 		break;
+	case SYS_ICC_HPPIR0_EL1:
 	case SYS_ICC_HPPIR1_EL1:
 		fn = __vgic_v3_read_hppir;
 		break;
-- 
2.11.0

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

* [PATCH v2 16/25] KVM: arm64: vgic-v3: Enable trapping of Group-0 system registers
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:21   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter, kvmarm,
	linux-arm-kernel

In order to be able to trap Group-0 GICv3 system registers, we need to
set ICH_HCR_EL2.TALL0 begore entering the guest. This is conditionnaly
done after having restored the guest's state, and cleared on exit.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/linux/irqchip/arm-gic-v3.h | 1 +
 virt/kvm/arm/vgic/vgic-v3.c        | 5 ++++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 03b5a28bb2d0..46a1e0943cf8 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -417,6 +417,7 @@
 
 #define ICH_HCR_EN			(1 << 0)
 #define ICH_HCR_UIE			(1 << 1)
+#define ICH_HCR_TALL0			(1 << 11)
 #define ICH_HCR_TALL1			(1 << 12)
 #define ICH_HCR_EOIcount_SHIFT		27
 #define ICH_HCR_EOIcount_MASK		(0x1f << ICH_HCR_EOIcount_SHIFT)
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index a16769276efd..7525216ef988 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -21,6 +21,7 @@
 
 #include "vgic.h"
 
+static bool group0_trap;
 static bool group1_trap;
 
 void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
@@ -241,6 +242,8 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
 
 	/* Get the show on the road... */
 	vgic_v3->vgic_hcr = ICH_HCR_EN;
+	if (group0_trap)
+		vgic_v3->vgic_hcr |= ICH_HCR_TALL0;
 	if (group1_trap)
 		vgic_v3->vgic_hcr |= ICH_HCR_TALL1;
 }
@@ -473,7 +476,7 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
 	if (kvm_vgic_global_state.vcpu_base == 0)
 		kvm_info("disabling GICv2 emulation\n");
 
-	if (group1_trap) {
+	if (group0_trap || group1_trap) {
 		kvm_info("GICv3 sysreg trapping enabled (reduced performance)\n");
 		static_branch_enable(&vgic_v3_cpuif_trap);
 	}
-- 
2.11.0

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

* [PATCH v2 16/25] KVM: arm64: vgic-v3: Enable trapping of Group-0 system registers
@ 2017-06-01 10:21   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

In order to be able to trap Group-0 GICv3 system registers, we need to
set ICH_HCR_EL2.TALL0 begore entering the guest. This is conditionnaly
done after having restored the guest's state, and cleared on exit.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/linux/irqchip/arm-gic-v3.h | 1 +
 virt/kvm/arm/vgic/vgic-v3.c        | 5 ++++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 03b5a28bb2d0..46a1e0943cf8 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -417,6 +417,7 @@
 
 #define ICH_HCR_EN			(1 << 0)
 #define ICH_HCR_UIE			(1 << 1)
+#define ICH_HCR_TALL0			(1 << 11)
 #define ICH_HCR_TALL1			(1 << 12)
 #define ICH_HCR_EOIcount_SHIFT		27
 #define ICH_HCR_EOIcount_MASK		(0x1f << ICH_HCR_EOIcount_SHIFT)
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index a16769276efd..7525216ef988 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -21,6 +21,7 @@
 
 #include "vgic.h"
 
+static bool group0_trap;
 static bool group1_trap;
 
 void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
@@ -241,6 +242,8 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
 
 	/* Get the show on the road... */
 	vgic_v3->vgic_hcr = ICH_HCR_EN;
+	if (group0_trap)
+		vgic_v3->vgic_hcr |= ICH_HCR_TALL0;
 	if (group1_trap)
 		vgic_v3->vgic_hcr |= ICH_HCR_TALL1;
 }
@@ -473,7 +476,7 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
 	if (kvm_vgic_global_state.vcpu_base == 0)
 		kvm_info("disabling GICv2 emulation\n");
 
-	if (group1_trap) {
+	if (group0_trap || group1_trap) {
 		kvm_info("GICv3 sysreg trapping enabled (reduced performance)\n");
 		static_branch_enable(&vgic_v3_cpuif_trap);
 	}
-- 
2.11.0

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

* [PATCH v2 17/25] KVM: arm64: Enable GICv3 Group-0 sysreg trapping via command-line
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:21   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter, kvmarm,
	linux-arm-kernel

Now that we're able to safely handle Group-0 sysreg access, let's
give the user the opportunity to enable it by passing a specific
command-line option (vgic_v3.group0_trap).

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/vgic/vgic-v3.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 7525216ef988..1486ce25edcb 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -419,6 +419,12 @@ int vgic_v3_map_resources(struct kvm *kvm)
 
 DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap);
 
+static int __init early_group0_trap_cfg(char *buf)
+{
+	return strtobool(buf, &group0_trap);
+}
+early_param("vgic_v3.group0_trap", early_group0_trap_cfg);
+
 static int __init early_group1_trap_cfg(char *buf)
 {
 	return strtobool(buf, &group1_trap);
-- 
2.11.0

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

* [PATCH v2 17/25] KVM: arm64: Enable GICv3 Group-0 sysreg trapping via command-line
@ 2017-06-01 10:21   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

Now that we're able to safely handle Group-0 sysreg access, let's
give the user the opportunity to enable it by passing a specific
command-line option (vgic_v3.group0_trap).

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/vgic/vgic-v3.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 7525216ef988..1486ce25edcb 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -419,6 +419,12 @@ int vgic_v3_map_resources(struct kvm *kvm)
 
 DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap);
 
+static int __init early_group0_trap_cfg(char *buf)
+{
+	return strtobool(buf, &group0_trap);
+}
+early_param("vgic_v3.group0_trap", early_group0_trap_cfg);
+
 static int __init early_group1_trap_cfg(char *buf)
 {
 	return strtobool(buf, &group1_trap);
-- 
2.11.0

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

* [PATCH v2 18/25] arm64: Add MIDR values for Cavium cn83XX SoCs
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:21   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter, kvmarm,
	linux-arm-kernel

From: David Daney <david.daney@cavium.com>

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/cputype.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index 0984d1b3a8f2..235e77d98261 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -86,6 +86,7 @@
 
 #define CAVIUM_CPU_PART_THUNDERX	0x0A1
 #define CAVIUM_CPU_PART_THUNDERX_81XX	0x0A2
+#define CAVIUM_CPU_PART_THUNDERX_83XX	0x0A3
 
 #define BRCM_CPU_PART_VULCAN		0x516
 
@@ -96,6 +97,7 @@
 #define MIDR_CORTEX_A73 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A73)
 #define MIDR_THUNDERX	MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
 #define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
+#define MIDR_THUNDERX_83XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_83XX)
 #define MIDR_QCOM_FALKOR_V1 MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_FALKOR_V1)
 
 #ifndef __ASSEMBLY__
-- 
2.11.0

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

* [PATCH v2 18/25] arm64: Add MIDR values for Cavium cn83XX SoCs
@ 2017-06-01 10:21   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

From: David Daney <david.daney@cavium.com>

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/cputype.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index 0984d1b3a8f2..235e77d98261 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -86,6 +86,7 @@
 
 #define CAVIUM_CPU_PART_THUNDERX	0x0A1
 #define CAVIUM_CPU_PART_THUNDERX_81XX	0x0A2
+#define CAVIUM_CPU_PART_THUNDERX_83XX	0x0A3
 
 #define BRCM_CPU_PART_VULCAN		0x516
 
@@ -96,6 +97,7 @@
 #define MIDR_CORTEX_A73 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A73)
 #define MIDR_THUNDERX	MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
 #define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
+#define MIDR_THUNDERX_83XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_83XX)
 #define MIDR_QCOM_FALKOR_V1 MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, QCOM_CPU_PART_FALKOR_V1)
 
 #ifndef __ASSEMBLY__
-- 
2.11.0

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

* [PATCH v2 19/25] arm64: Add workaround for Cavium Thunder erratum 30115
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:21   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter, kvmarm,
	linux-arm-kernel

From: David Daney <david.daney@cavium.com>

Some Cavium Thunder CPUs suffer a problem where a KVM guest may
inadvertently cause the host kernel to quit receiving interrupts.

Use the Group-0/1 trapping in order to deal with it.

[maz]: Adapted patch to the Group-0/1 trapping, reworked commit log

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 Documentation/arm64/silicon-errata.txt |  1 +
 arch/arm64/Kconfig                     | 11 +++++++++++
 arch/arm64/include/asm/cpucaps.h       |  3 ++-
 arch/arm64/kernel/cpu_errata.c         | 21 +++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c            |  7 +++++++
 5 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt
index 10f2dddbf449..f5f93dca54b7 100644
--- a/Documentation/arm64/silicon-errata.txt
+++ b/Documentation/arm64/silicon-errata.txt
@@ -62,6 +62,7 @@ stable kernels.
 | Cavium         | ThunderX GICv3  | #23154          | CAVIUM_ERRATUM_23154        |
 | Cavium         | ThunderX Core   | #27456          | CAVIUM_ERRATUM_27456        |
 | Cavium         | ThunderX SMMUv2 | #27704          | N/A                         |
+| Cavium         | ThunderX Core   | #30115          | CAVIUM_ERRATUM_30115        |
 |                |                 |                 |                             |
 | Freescale/NXP  | LS2080A/LS1043A | A-008585        | FSL_ERRATUM_A008585         |
 |                |                 |                 |                             |
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 3dcd7ec69bca..0950b21e4d17 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -480,6 +480,17 @@ config CAVIUM_ERRATUM_27456
 
 	  If unsure, say Y.
 
+config CAVIUM_ERRATUM_30115
+	bool "Cavium erratum 30115: Guest may disable interrupts in host"
+	default y
+	help
+	  On ThunderX T88 pass 1.x through 2.2, T81 pass 1.0 through
+	  1.2, and T83 Pass 1.0, KVM guest execution may disable
+	  interrupts in host. Trapping GICv3 group-1 accesses sidesteps
+	  the issue.
+
+	  If unsure, say Y.
+
 config QCOM_FALKOR_ERRATUM_1003
 	bool "Falkor E1003: Incorrect translation due to ASID change"
 	default y
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
index b3aab8a17868..8d2272c6822c 100644
--- a/arch/arm64/include/asm/cpucaps.h
+++ b/arch/arm64/include/asm/cpucaps.h
@@ -38,7 +38,8 @@
 #define ARM64_WORKAROUND_REPEAT_TLBI		17
 #define ARM64_WORKAROUND_QCOM_FALKOR_E1003	18
 #define ARM64_WORKAROUND_858921			19
+#define ARM64_WORKAROUND_CAVIUM_30115		20
 
-#define ARM64_NCAPS				20
+#define ARM64_NCAPS				21
 
 #endif /* __ASM_CPUCAPS_H */
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 2ed2a7657711..0e27f86ee709 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -133,6 +133,27 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
 		MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x00),
 	},
 #endif
+#ifdef CONFIG_CAVIUM_ERRATUM_30115
+	{
+	/* Cavium ThunderX, T88 pass 1.x - 2.2 */
+		.desc = "Cavium erratum 30115",
+		.capability = ARM64_WORKAROUND_CAVIUM_30115,
+		MIDR_RANGE(MIDR_THUNDERX, 0x00,
+			   (1 << MIDR_VARIANT_SHIFT) | 2),
+	},
+	{
+	/* Cavium ThunderX, T81 pass 1.0 - 1.2 */
+		.desc = "Cavium erratum 30115",
+		.capability = ARM64_WORKAROUND_CAVIUM_30115,
+		MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x02),
+	},
+	{
+	/* Cavium ThunderX, T83 pass 1.0 */
+		.desc = "Cavium erratum 30115",
+		.capability = ARM64_WORKAROUND_CAVIUM_30115,
+		MIDR_RANGE(MIDR_THUNDERX_83XX, 0x00, 0x00),
+	},
+#endif
 	{
 		.desc = "Mismatched cache line size",
 		.capability = ARM64_MISMATCHED_CACHE_LINE_SIZE,
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 1486ce25edcb..062be1fe95b5 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -482,6 +482,13 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
 	if (kvm_vgic_global_state.vcpu_base == 0)
 		kvm_info("disabling GICv2 emulation\n");
 
+#ifdef CONFIG_ARM64
+	if (cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_30115)) {
+		group0_trap = true;
+		group1_trap = true;
+	}
+#endif
+
 	if (group0_trap || group1_trap) {
 		kvm_info("GICv3 sysreg trapping enabled (reduced performance)\n");
 		static_branch_enable(&vgic_v3_cpuif_trap);
-- 
2.11.0

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

* [PATCH v2 19/25] arm64: Add workaround for Cavium Thunder erratum 30115
@ 2017-06-01 10:21   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

From: David Daney <david.daney@cavium.com>

Some Cavium Thunder CPUs suffer a problem where a KVM guest may
inadvertently cause the host kernel to quit receiving interrupts.

Use the Group-0/1 trapping in order to deal with it.

[maz]: Adapted patch to the Group-0/1 trapping, reworked commit log

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 Documentation/arm64/silicon-errata.txt |  1 +
 arch/arm64/Kconfig                     | 11 +++++++++++
 arch/arm64/include/asm/cpucaps.h       |  3 ++-
 arch/arm64/kernel/cpu_errata.c         | 21 +++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c            |  7 +++++++
 5 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt
index 10f2dddbf449..f5f93dca54b7 100644
--- a/Documentation/arm64/silicon-errata.txt
+++ b/Documentation/arm64/silicon-errata.txt
@@ -62,6 +62,7 @@ stable kernels.
 | Cavium         | ThunderX GICv3  | #23154          | CAVIUM_ERRATUM_23154        |
 | Cavium         | ThunderX Core   | #27456          | CAVIUM_ERRATUM_27456        |
 | Cavium         | ThunderX SMMUv2 | #27704          | N/A                         |
+| Cavium         | ThunderX Core   | #30115          | CAVIUM_ERRATUM_30115        |
 |                |                 |                 |                             |
 | Freescale/NXP  | LS2080A/LS1043A | A-008585        | FSL_ERRATUM_A008585         |
 |                |                 |                 |                             |
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 3dcd7ec69bca..0950b21e4d17 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -480,6 +480,17 @@ config CAVIUM_ERRATUM_27456
 
 	  If unsure, say Y.
 
+config CAVIUM_ERRATUM_30115
+	bool "Cavium erratum 30115: Guest may disable interrupts in host"
+	default y
+	help
+	  On ThunderX T88 pass 1.x through 2.2, T81 pass 1.0 through
+	  1.2, and T83 Pass 1.0, KVM guest execution may disable
+	  interrupts in host. Trapping GICv3 group-1 accesses sidesteps
+	  the issue.
+
+	  If unsure, say Y.
+
 config QCOM_FALKOR_ERRATUM_1003
 	bool "Falkor E1003: Incorrect translation due to ASID change"
 	default y
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
index b3aab8a17868..8d2272c6822c 100644
--- a/arch/arm64/include/asm/cpucaps.h
+++ b/arch/arm64/include/asm/cpucaps.h
@@ -38,7 +38,8 @@
 #define ARM64_WORKAROUND_REPEAT_TLBI		17
 #define ARM64_WORKAROUND_QCOM_FALKOR_E1003	18
 #define ARM64_WORKAROUND_858921			19
+#define ARM64_WORKAROUND_CAVIUM_30115		20
 
-#define ARM64_NCAPS				20
+#define ARM64_NCAPS				21
 
 #endif /* __ASM_CPUCAPS_H */
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 2ed2a7657711..0e27f86ee709 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -133,6 +133,27 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
 		MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x00),
 	},
 #endif
+#ifdef CONFIG_CAVIUM_ERRATUM_30115
+	{
+	/* Cavium ThunderX, T88 pass 1.x - 2.2 */
+		.desc = "Cavium erratum 30115",
+		.capability = ARM64_WORKAROUND_CAVIUM_30115,
+		MIDR_RANGE(MIDR_THUNDERX, 0x00,
+			   (1 << MIDR_VARIANT_SHIFT) | 2),
+	},
+	{
+	/* Cavium ThunderX, T81 pass 1.0 - 1.2 */
+		.desc = "Cavium erratum 30115",
+		.capability = ARM64_WORKAROUND_CAVIUM_30115,
+		MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x02),
+	},
+	{
+	/* Cavium ThunderX, T83 pass 1.0 */
+		.desc = "Cavium erratum 30115",
+		.capability = ARM64_WORKAROUND_CAVIUM_30115,
+		MIDR_RANGE(MIDR_THUNDERX_83XX, 0x00, 0x00),
+	},
+#endif
 	{
 		.desc = "Mismatched cache line size",
 		.capability = ARM64_MISMATCHED_CACHE_LINE_SIZE,
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 1486ce25edcb..062be1fe95b5 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -482,6 +482,13 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
 	if (kvm_vgic_global_state.vcpu_base == 0)
 		kvm_info("disabling GICv2 emulation\n");
 
+#ifdef CONFIG_ARM64
+	if (cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_30115)) {
+		group0_trap = true;
+		group1_trap = true;
+	}
+#endif
+
 	if (group0_trap || group1_trap) {
 		kvm_info("GICv3 sysreg trapping enabled (reduced performance)\n");
 		static_branch_enable(&vgic_v3_cpuif_trap);
-- 
2.11.0

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

* [PATCH v2 20/25] KVM: arm64: vgic-v3: Add ICV_DIR_EL1 handler
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:21   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter, kvmarm,
	linux-arm-kernel

Add a handler for writing the guest's view of the ICC_DIR_EL1
register, performing the deactivation of an interrupt if EOImode
is set ot 1.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/hyp/vgic-v3-sr.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 5ff788d308ee..b86a0776c407 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -634,6 +634,30 @@ static void __hyp_text __vgic_v3_bump_eoicount(void)
 	write_gicreg(hcr, ICH_HCR_EL2);
 }
 
+static void __hyp_text __vgic_v3_write_dir(struct kvm_vcpu *vcpu,
+					   u32 vmcr, int rt)
+{
+	u32 vid = vcpu_get_reg(vcpu, rt);
+	u64 lr_val;
+	int lr;
+
+	/* EOImode == 0, nothing to be done here */
+	if (!(vmcr & ICH_VMCR_EOIM_MASK))
+		return;
+
+	/* No deactivate to be performed on an LPI */
+	if (vid >= VGIC_MIN_LPI)
+		return;
+
+	lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val);
+	if (lr == -1) {
+		__vgic_v3_bump_eoicount();
+		return;
+	}
+
+	__vgic_v3_clear_active_lr(lr, lr_val);
+}
+
 static void __hyp_text __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
 	u32 vid = vcpu_get_reg(vcpu, rt);
@@ -936,6 +960,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 		else
 			fn = __vgic_v3_write_bpr0;
 		break;
+	case SYS_ICC_DIR_EL1:
+		fn = __vgic_v3_write_dir;
+		break;
 	default:
 		return 0;
 	}
-- 
2.11.0

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

* [PATCH v2 20/25] KVM: arm64: vgic-v3: Add ICV_DIR_EL1 handler
@ 2017-06-01 10:21   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

Add a handler for writing the guest's view of the ICC_DIR_EL1
register, performing the deactivation of an interrupt if EOImode
is set ot 1.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/hyp/vgic-v3-sr.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 5ff788d308ee..b86a0776c407 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -634,6 +634,30 @@ static void __hyp_text __vgic_v3_bump_eoicount(void)
 	write_gicreg(hcr, ICH_HCR_EL2);
 }
 
+static void __hyp_text __vgic_v3_write_dir(struct kvm_vcpu *vcpu,
+					   u32 vmcr, int rt)
+{
+	u32 vid = vcpu_get_reg(vcpu, rt);
+	u64 lr_val;
+	int lr;
+
+	/* EOImode == 0, nothing to be done here */
+	if (!(vmcr & ICH_VMCR_EOIM_MASK))
+		return;
+
+	/* No deactivate to be performed on an LPI */
+	if (vid >= VGIC_MIN_LPI)
+		return;
+
+	lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val);
+	if (lr == -1) {
+		__vgic_v3_bump_eoicount();
+		return;
+	}
+
+	__vgic_v3_clear_active_lr(lr, lr_val);
+}
+
 static void __hyp_text __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
 {
 	u32 vid = vcpu_get_reg(vcpu, rt);
@@ -936,6 +960,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 		else
 			fn = __vgic_v3_write_bpr0;
 		break;
+	case SYS_ICC_DIR_EL1:
+		fn = __vgic_v3_write_dir;
+		break;
 	default:
 		return 0;
 	}
-- 
2.11.0

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

* [PATCH v2 21/25] KVM: arm64: vgic-v3: Add ICV_RPR_EL1 handler
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:21   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter, kvmarm,
	linux-arm-kernel

Add a handler for reading the guest's view of the ICV_RPR_EL1
register, returning the highest active priority.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/sysreg.h |  1 +
 virt/kvm/arm/hyp/vgic-v3-sr.c   | 10 ++++++++++
 2 files changed, 11 insertions(+)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 9971c5c435a7..c4d48e403629 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -187,6 +187,7 @@
 #define SYS_ICC_AP0Rn_EL1(n)		sys_reg(3, 0, 12, 8, 4 | n)
 #define SYS_ICC_AP1Rn_EL1(n)		sys_reg(3, 0, 12, 9, n)
 #define SYS_ICC_DIR_EL1			sys_reg(3, 0, 12, 11, 1)
+#define SYS_ICC_RPR_EL1			sys_reg(3, 0, 12, 11, 3)
 #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
 #define SYS_ICC_IAR1_EL1		sys_reg(3, 0, 12, 12, 0)
 #define SYS_ICC_EOIR1_EL1		sys_reg(3, 0, 12, 12, 1)
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index b86a0776c407..cac9d563d97d 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -874,6 +874,13 @@ static void __hyp_text __vgic_v3_read_hppir(struct kvm_vcpu *vcpu,
 	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
 }
 
+static void __hyp_text __vgic_v3_read_rpr(struct kvm_vcpu *vcpu,
+					  u32 vmcr, int rt)
+{
+	u32 val = __vgic_v3_get_highest_active_priority();
+	vcpu_set_reg(vcpu, rt, val);
+}
+
 int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 {
 	int rt;
@@ -963,6 +970,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 	case SYS_ICC_DIR_EL1:
 		fn = __vgic_v3_write_dir;
 		break;
+	case SYS_ICC_RPR_EL1:
+		fn = __vgic_v3_read_rpr;
+		break;
 	default:
 		return 0;
 	}
-- 
2.11.0

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

* [PATCH v2 21/25] KVM: arm64: vgic-v3: Add ICV_RPR_EL1 handler
@ 2017-06-01 10:21   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

Add a handler for reading the guest's view of the ICV_RPR_EL1
register, returning the highest active priority.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm64/include/asm/sysreg.h |  1 +
 virt/kvm/arm/hyp/vgic-v3-sr.c   | 10 ++++++++++
 2 files changed, 11 insertions(+)

diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 9971c5c435a7..c4d48e403629 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -187,6 +187,7 @@
 #define SYS_ICC_AP0Rn_EL1(n)		sys_reg(3, 0, 12, 8, 4 | n)
 #define SYS_ICC_AP1Rn_EL1(n)		sys_reg(3, 0, 12, 9, n)
 #define SYS_ICC_DIR_EL1			sys_reg(3, 0, 12, 11, 1)
+#define SYS_ICC_RPR_EL1			sys_reg(3, 0, 12, 11, 3)
 #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
 #define SYS_ICC_IAR1_EL1		sys_reg(3, 0, 12, 12, 0)
 #define SYS_ICC_EOIR1_EL1		sys_reg(3, 0, 12, 12, 1)
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index b86a0776c407..cac9d563d97d 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -874,6 +874,13 @@ static void __hyp_text __vgic_v3_read_hppir(struct kvm_vcpu *vcpu,
 	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
 }
 
+static void __hyp_text __vgic_v3_read_rpr(struct kvm_vcpu *vcpu,
+					  u32 vmcr, int rt)
+{
+	u32 val = __vgic_v3_get_highest_active_priority();
+	vcpu_set_reg(vcpu, rt, val);
+}
+
 int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 {
 	int rt;
@@ -963,6 +970,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 	case SYS_ICC_DIR_EL1:
 		fn = __vgic_v3_write_dir;
 		break;
+	case SYS_ICC_RPR_EL1:
+		fn = __vgic_v3_read_rpr;
+		break;
 	default:
 		return 0;
 	}
-- 
2.11.0

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

* [PATCH v2 22/25] KVM: arm64: vgic-v3: Add ICV_CTLR_EL1 handler
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:21   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter, kvmarm,
	linux-arm-kernel

Add a handler for reading/writing the guest's view of the ICV_CTLR_EL1
register. only EOIMode and CBPR are of interest here, as all the other
bits directly come from ICH_VTR_EL2 and are Read-Only.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/hyp/vgic-v3-sr.c | 46 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index cac9d563d97d..3a5749e6c797 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -881,6 +881,46 @@ static void __hyp_text __vgic_v3_read_rpr(struct kvm_vcpu *vcpu,
 	vcpu_set_reg(vcpu, rt, val);
 }
 
+static void __hyp_text __vgic_v3_read_ctlr(struct kvm_vcpu *vcpu,
+					   u32 vmcr, int rt)
+{
+	u32 vtr, val;
+
+	vtr = read_gicreg(ICH_VTR_EL2);
+	/* PRIbits */
+	val = ((vtr >> 29) & 7) << ICC_CTLR_EL1_PRI_BITS_SHIFT;
+	/* IDbits */
+	val |= ((vtr >> 23) & 7) << ICC_CTLR_EL1_ID_BITS_SHIFT;
+	/* SEIS */
+	val |= ((vtr >> 22) & 1) << ICC_CTLR_EL1_SEIS_SHIFT;
+	/* A3V */
+	val |= ((vtr >> 21) & 1) << ICC_CTLR_EL1_A3V_SHIFT;
+	/* EOImode */
+	val |= ((vmcr & ICH_VMCR_EOIM_MASK) >> ICH_VMCR_EOIM_SHIFT) << ICC_CTLR_EL1_EOImode_SHIFT;
+	/* CBPR */
+	val |= (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT;
+
+	vcpu_set_reg(vcpu, rt, val);
+}
+
+static void __hyp_text __vgic_v3_write_ctlr(struct kvm_vcpu *vcpu,
+					    u32 vmcr, int rt)
+{
+	u32 val = vcpu_get_reg(vcpu, rt);
+
+	if (val & ICC_CTLR_EL1_CBPR_MASK)
+		vmcr |= ICH_VMCR_CBPR_MASK;
+	else
+		vmcr &= ~ICH_VMCR_CBPR_MASK;
+
+	if (val & ICC_CTLR_EL1_EOImode_MASK)
+		vmcr |= ICH_VMCR_EOIM_MASK;
+	else
+		vmcr &= ~ICH_VMCR_EOIM_MASK;
+
+	write_gicreg(vmcr, ICH_VMCR_EL2);
+}
+
 int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 {
 	int rt;
@@ -973,6 +1013,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 	case SYS_ICC_RPR_EL1:
 		fn = __vgic_v3_read_rpr;
 		break;
+	case SYS_ICC_CTLR_EL1:
+		if (is_read)
+			fn = __vgic_v3_read_ctlr;
+		else
+			fn = __vgic_v3_write_ctlr;
+		break;
 	default:
 		return 0;
 	}
-- 
2.11.0

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

* [PATCH v2 22/25] KVM: arm64: vgic-v3: Add ICV_CTLR_EL1 handler
@ 2017-06-01 10:21   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

Add a handler for reading/writing the guest's view of the ICV_CTLR_EL1
register. only EOIMode and CBPR are of interest here, as all the other
bits directly come from ICH_VTR_EL2 and are Read-Only.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/hyp/vgic-v3-sr.c | 46 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index cac9d563d97d..3a5749e6c797 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -881,6 +881,46 @@ static void __hyp_text __vgic_v3_read_rpr(struct kvm_vcpu *vcpu,
 	vcpu_set_reg(vcpu, rt, val);
 }
 
+static void __hyp_text __vgic_v3_read_ctlr(struct kvm_vcpu *vcpu,
+					   u32 vmcr, int rt)
+{
+	u32 vtr, val;
+
+	vtr = read_gicreg(ICH_VTR_EL2);
+	/* PRIbits */
+	val = ((vtr >> 29) & 7) << ICC_CTLR_EL1_PRI_BITS_SHIFT;
+	/* IDbits */
+	val |= ((vtr >> 23) & 7) << ICC_CTLR_EL1_ID_BITS_SHIFT;
+	/* SEIS */
+	val |= ((vtr >> 22) & 1) << ICC_CTLR_EL1_SEIS_SHIFT;
+	/* A3V */
+	val |= ((vtr >> 21) & 1) << ICC_CTLR_EL1_A3V_SHIFT;
+	/* EOImode */
+	val |= ((vmcr & ICH_VMCR_EOIM_MASK) >> ICH_VMCR_EOIM_SHIFT) << ICC_CTLR_EL1_EOImode_SHIFT;
+	/* CBPR */
+	val |= (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT;
+
+	vcpu_set_reg(vcpu, rt, val);
+}
+
+static void __hyp_text __vgic_v3_write_ctlr(struct kvm_vcpu *vcpu,
+					    u32 vmcr, int rt)
+{
+	u32 val = vcpu_get_reg(vcpu, rt);
+
+	if (val & ICC_CTLR_EL1_CBPR_MASK)
+		vmcr |= ICH_VMCR_CBPR_MASK;
+	else
+		vmcr &= ~ICH_VMCR_CBPR_MASK;
+
+	if (val & ICC_CTLR_EL1_EOImode_MASK)
+		vmcr |= ICH_VMCR_EOIM_MASK;
+	else
+		vmcr &= ~ICH_VMCR_EOIM_MASK;
+
+	write_gicreg(vmcr, ICH_VMCR_EL2);
+}
+
 int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 {
 	int rt;
@@ -973,6 +1013,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 	case SYS_ICC_RPR_EL1:
 		fn = __vgic_v3_read_rpr;
 		break;
+	case SYS_ICC_CTLR_EL1:
+		if (is_read)
+			fn = __vgic_v3_read_ctlr;
+		else
+			fn = __vgic_v3_write_ctlr;
+		break;
 	default:
 		return 0;
 	}
-- 
2.11.0

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

* [PATCH v2 23/25] KVM: arm64: vgic-v3: Add ICV_PMR_EL1 handler
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:21   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter, kvmarm,
	linux-arm-kernel

Add a handler for reading/writing the guest's view of the ICC_PMR_EL1
register, which is located in the ICH_VMCR_EL2.VPMR field.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/hyp/vgic-v3-sr.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 3a5749e6c797..3c6b7d46754a 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -874,6 +874,27 @@ static void __hyp_text __vgic_v3_read_hppir(struct kvm_vcpu *vcpu,
 	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
 }
 
+static void __hyp_text __vgic_v3_read_pmr(struct kvm_vcpu *vcpu,
+					  u32 vmcr, int rt)
+{
+	vmcr &= ICH_VMCR_PMR_MASK;
+	vmcr >>= ICH_VMCR_PMR_SHIFT;
+	vcpu_set_reg(vcpu, rt, vmcr);
+}
+
+static void __hyp_text __vgic_v3_write_pmr(struct kvm_vcpu *vcpu,
+					   u32 vmcr, int rt)
+{
+	u32 val = vcpu_get_reg(vcpu, rt);
+
+	val <<= ICH_VMCR_PMR_SHIFT;
+	val &= ICH_VMCR_PMR_MASK;
+	vmcr &= ~ICH_VMCR_PMR_MASK;
+	vmcr |= val;
+
+	write_gicreg(vmcr, ICH_VMCR_EL2);
+}
+
 static void __hyp_text __vgic_v3_read_rpr(struct kvm_vcpu *vcpu,
 					  u32 vmcr, int rt)
 {
@@ -1019,6 +1040,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 		else
 			fn = __vgic_v3_write_ctlr;
 		break;
+	case SYS_ICC_PMR_EL1:
+		if (is_read)
+			fn = __vgic_v3_read_pmr;
+		else
+			fn = __vgic_v3_write_pmr;
+		break;
 	default:
 		return 0;
 	}
-- 
2.11.0

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

* [PATCH v2 23/25] KVM: arm64: vgic-v3: Add ICV_PMR_EL1 handler
@ 2017-06-01 10:21   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

Add a handler for reading/writing the guest's view of the ICC_PMR_EL1
register, which is located in the ICH_VMCR_EL2.VPMR field.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/hyp/vgic-v3-sr.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 3a5749e6c797..3c6b7d46754a 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -874,6 +874,27 @@ static void __hyp_text __vgic_v3_read_hppir(struct kvm_vcpu *vcpu,
 	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
 }
 
+static void __hyp_text __vgic_v3_read_pmr(struct kvm_vcpu *vcpu,
+					  u32 vmcr, int rt)
+{
+	vmcr &= ICH_VMCR_PMR_MASK;
+	vmcr >>= ICH_VMCR_PMR_SHIFT;
+	vcpu_set_reg(vcpu, rt, vmcr);
+}
+
+static void __hyp_text __vgic_v3_write_pmr(struct kvm_vcpu *vcpu,
+					   u32 vmcr, int rt)
+{
+	u32 val = vcpu_get_reg(vcpu, rt);
+
+	val <<= ICH_VMCR_PMR_SHIFT;
+	val &= ICH_VMCR_PMR_MASK;
+	vmcr &= ~ICH_VMCR_PMR_MASK;
+	vmcr |= val;
+
+	write_gicreg(vmcr, ICH_VMCR_EL2);
+}
+
 static void __hyp_text __vgic_v3_read_rpr(struct kvm_vcpu *vcpu,
 					  u32 vmcr, int rt)
 {
@@ -1019,6 +1040,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
 		else
 			fn = __vgic_v3_write_ctlr;
 		break;
+	case SYS_ICC_PMR_EL1:
+		if (is_read)
+			fn = __vgic_v3_read_pmr;
+		else
+			fn = __vgic_v3_write_pmr;
+		break;
 	default:
 		return 0;
 	}
-- 
2.11.0

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

* [PATCH v2 24/25] KVM: arm64: Enable GICv3 common sysreg trapping via command-line
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:21   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter, kvmarm,
	linux-arm-kernel

Now that we're able to safely handle common sysreg access, let's
give the user the opportunity to enable it by passing a specific
command-line option (vgic_v3.common_trap).

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/linux/irqchip/arm-gic-v3.h |  1 +
 virt/kvm/arm/vgic/vgic-v3.c        | 11 ++++++++++-
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 46a1e0943cf8..f0cebb6e57d0 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -417,6 +417,7 @@
 
 #define ICH_HCR_EN			(1 << 0)
 #define ICH_HCR_UIE			(1 << 1)
+#define ICH_HCR_TC			(1 << 10)
 #define ICH_HCR_TALL0			(1 << 11)
 #define ICH_HCR_TALL1			(1 << 12)
 #define ICH_HCR_EOIcount_SHIFT		27
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 062be1fe95b5..636f1258d217 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -23,6 +23,7 @@
 
 static bool group0_trap;
 static bool group1_trap;
+static bool common_trap;
 
 void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
 {
@@ -246,6 +247,8 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
 		vgic_v3->vgic_hcr |= ICH_HCR_TALL0;
 	if (group1_trap)
 		vgic_v3->vgic_hcr |= ICH_HCR_TALL1;
+	if (common_trap)
+		vgic_v3->vgic_hcr |= ICH_HCR_TC;
 }
 
 int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq)
@@ -431,6 +434,12 @@ static int __init early_group1_trap_cfg(char *buf)
 }
 early_param("vgic_v3.group1_trap", early_group1_trap_cfg);
 
+static int __init early_common_trap_cfg(char *buf)
+{
+	return strtobool(buf, &common_trap);
+}
+early_param("vgic_v3.common_trap", early_common_trap_cfg);
+
 /**
  * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
  * @node:	pointer to the DT node
@@ -489,7 +498,7 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
 	}
 #endif
 
-	if (group0_trap || group1_trap) {
+	if (group0_trap || group1_trap || common_trap) {
 		kvm_info("GICv3 sysreg trapping enabled (reduced performance)\n");
 		static_branch_enable(&vgic_v3_cpuif_trap);
 	}
-- 
2.11.0

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

* [PATCH v2 24/25] KVM: arm64: Enable GICv3 common sysreg trapping via command-line
@ 2017-06-01 10:21   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

Now that we're able to safely handle common sysreg access, let's
give the user the opportunity to enable it by passing a specific
command-line option (vgic_v3.common_trap).

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/linux/irqchip/arm-gic-v3.h |  1 +
 virt/kvm/arm/vgic/vgic-v3.c        | 11 ++++++++++-
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index 46a1e0943cf8..f0cebb6e57d0 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -417,6 +417,7 @@
 
 #define ICH_HCR_EN			(1 << 0)
 #define ICH_HCR_UIE			(1 << 1)
+#define ICH_HCR_TC			(1 << 10)
 #define ICH_HCR_TALL0			(1 << 11)
 #define ICH_HCR_TALL1			(1 << 12)
 #define ICH_HCR_EOIcount_SHIFT		27
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 062be1fe95b5..636f1258d217 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -23,6 +23,7 @@
 
 static bool group0_trap;
 static bool group1_trap;
+static bool common_trap;
 
 void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
 {
@@ -246,6 +247,8 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
 		vgic_v3->vgic_hcr |= ICH_HCR_TALL0;
 	if (group1_trap)
 		vgic_v3->vgic_hcr |= ICH_HCR_TALL1;
+	if (common_trap)
+		vgic_v3->vgic_hcr |= ICH_HCR_TC;
 }
 
 int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq)
@@ -431,6 +434,12 @@ static int __init early_group1_trap_cfg(char *buf)
 }
 early_param("vgic_v3.group1_trap", early_group1_trap_cfg);
 
+static int __init early_common_trap_cfg(char *buf)
+{
+	return strtobool(buf, &common_trap);
+}
+early_param("vgic_v3.common_trap", early_common_trap_cfg);
+
 /**
  * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
  * @node:	pointer to the DT node
@@ -489,7 +498,7 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
 	}
 #endif
 
-	if (group0_trap || group1_trap) {
+	if (group0_trap || group1_trap || common_trap) {
 		kvm_info("GICv3 sysreg trapping enabled (reduced performance)\n");
 		static_branch_enable(&vgic_v3_cpuif_trap);
 	}
-- 
2.11.0

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

* [PATCH v2 25/25] KVM: arm64: vgic-v3: Log which GICv3 system registers are trapped
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 10:21   ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter, kvmarm,
	linux-arm-kernel

In order to facilitate debug, let's log which class of GICv3 system
registers are trapped.

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

diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 636f1258d217..e0b530f4b1e6 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -499,7 +499,10 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
 #endif
 
 	if (group0_trap || group1_trap || common_trap) {
-		kvm_info("GICv3 sysreg trapping enabled (reduced performance)\n");
+		kvm_info("GICv3 sysreg trapping enabled ([%s%s%s], reduced performance)\n",
+			 group0_trap ? "G0" : "",
+			 group1_trap ? "G1" : "",
+			 common_trap ? "C"  : "");
 		static_branch_enable(&vgic_v3_cpuif_trap);
 	}
 
-- 
2.11.0

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

* [PATCH v2 25/25] KVM: arm64: vgic-v3: Log which GICv3 system registers are trapped
@ 2017-06-01 10:21   ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-01 10:21 UTC (permalink / raw)
  To: linux-arm-kernel

In order to facilitate debug, let's log which class of GICv3 system
registers are trapped.

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

diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 636f1258d217..e0b530f4b1e6 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -499,7 +499,10 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
 #endif
 
 	if (group0_trap || group1_trap || common_trap) {
-		kvm_info("GICv3 sysreg trapping enabled (reduced performance)\n");
+		kvm_info("GICv3 sysreg trapping enabled ([%s%s%s], reduced performance)\n",
+			 group0_trap ? "G0" : "",
+			 group1_trap ? "G1" : "",
+			 common_trap ? "C"  : "");
 		static_branch_enable(&vgic_v3_cpuif_trap);
 	}
 
-- 
2.11.0

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

* Re: [PATCH v2 00/25] arm64: KVM: Mediate access to GICv3 sysregs at EL2
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-01 21:00   ` David Daney
  -1 siblings, 0 replies; 152+ messages in thread
From: David Daney @ 2017-06-01 21:00 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter, kvmarm,
	linux-arm-kernel

On 06/01/2017 03:20 AM, Marc Zyngier wrote:
> Some systems have less than perfect GICv3 implementations, leading to
> all kind of ugly issues (guest hanging, host dying). In order to allow
> some level of diagnostic, and in some cases implement workarounds,
> this series enables the trapping of both Group-0, Group-1 and Common
> sysregs. Mediating the access at EL2 allows some form of sanity
> checking that the HW is sometimes sorely lacking.
> 
> Instead of fully emulating a GICv3 CPU interface, we still use the
> existing HW (list registers, AP registers, VMCR...), which allows the
> code to be independent from the rest of the KVM code, and to cope with
> partial trapping.
> 
> Of course, trapping has a cost, which is why this must be either
> enabled on the command line, or selected by another cpu capability
> (see Cavium erratum 30115). A quick test on an A57-based platform
> shows a 25% hit when repeatedly banging on the trapped registers,
> while normal workloads do not seem to suffer noticeably from such
> trapping (hackbench variance is in the usual noise, despite being very
> IPI happy).
> 
> This has been tested on a dual socket Thundex-X and a Freescale LS-2085a.
> 
> I've taken the liberty to rebase David Daney's initial Cavium erratum
> 30115 workaround on top of this series, and included it here as a
> typical use case.

I pulled this from:

 
https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git/log/?h=kvm-arm64/gicv3-cpuif-mediated-access

this morning at commit	58c1763c5aa6223ab3d04e0c183a31eb0aef832e

Entire series tested by and

Acked-by: David Daney <david.daney@cavium.com>

Thanks again.

> 
> - From v1:
>    * Fix bug in DIR handling which would have performed a deactivation even
>      when EOImode==0
>    * Some minor cleanups and clarifications.
>    * All the initial fixes have already been merged.
>    * Rebased on 4.12-rc3.
> 
> David Daney (2):
>    arm64: Add MIDR values for Cavium cn83XX SoCs
>    arm64: Add workaround for Cavium Thunder erratum 30115
> 
> Marc Zyngier (23):
>    arm64: Add a facility to turn an ESR syndrome into a sysreg encoding
>    KVM: arm/arm64: vgic-v3: Add accessors for the ICH_APxRn_EL2 registers
>    KVM: arm64: Make kvm_condition_valid32() accessible from EL2
>    KVM: arm64: vgic-v3: Add hook to handle guest GICv3 sysreg accesses at
>      EL2
>    KVM: arm64: vgic-v3: Add ICV_BPR1_EL1 handler
>    KVM: arm64: vgic-v3: Add ICV_IGRPEN1_EL1 handler
>    KVM: arm64: vgic-v3: Add ICV_IAR1_EL1 handler
>    KVM: arm64: vgic-v3: Add ICV_EOIR1_EL1 handler
>    KVM: arm64: vgic-v3: Add ICV_AP1Rn_EL1 handler
>    KVM: arm64: vgic-v3: Add ICV_HPPIR1_EL1 handler
>    KVM: arm64: vgic-v3: Enable trapping of Group-1 system registers
>    KVM: arm64: Enable GICv3 Group-1 sysreg trapping via command-line
>    KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler
>    KVM: arm64: vgic-v3: Add ICV_IGNREN0_EL1 handler
>    KVM: arm64: vgic-v3: Add misc Group-0 handlers
>    KVM: arm64: vgic-v3: Enable trapping of Group-0 system registers
>    KVM: arm64: Enable GICv3 Group-0 sysreg trapping via command-line
>    KVM: arm64: vgic-v3: Add ICV_DIR_EL1 handler
>    KVM: arm64: vgic-v3: Add ICV_RPR_EL1 handler
>    KVM: arm64: vgic-v3: Add ICV_CTLR_EL1 handler
>    KVM: arm64: vgic-v3: Add ICV_PMR_EL1 handler
>    KVM: arm64: Enable GICv3 common sysreg trapping via command-line
>    KVM: arm64: vgic-v3: Log which GICv3 system registers are trapped
> 
>   Documentation/arm64/silicon-errata.txt |   1 +
>   arch/arm64/Kconfig                     |  11 +
>   arch/arm64/include/asm/cpucaps.h       |   3 +-
>   arch/arm64/include/asm/cputype.h       |   2 +
>   arch/arm64/include/asm/esr.h           |  24 +
>   arch/arm64/include/asm/kvm_hyp.h       |   1 +
>   arch/arm64/include/asm/sysreg.h        |   9 +
>   arch/arm64/kernel/cpu_errata.c         |  21 +
>   arch/arm64/kvm/hyp/switch.c            |  14 +
>   include/kvm/arm_vgic.h                 |   1 +
>   include/linux/irqchip/arm-gic-v3.h     |   6 +
>   virt/kvm/arm/aarch32.c                 |   2 +-
>   virt/kvm/arm/hyp/vgic-v3-sr.c          | 803 ++++++++++++++++++++++++++++++++-
>   virt/kvm/arm/vgic/vgic-v3.c            |  45 ++
>   14 files changed, 925 insertions(+), 18 deletions(-)
> 

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

* [PATCH v2 00/25] arm64: KVM: Mediate access to GICv3 sysregs at EL2
@ 2017-06-01 21:00   ` David Daney
  0 siblings, 0 replies; 152+ messages in thread
From: David Daney @ 2017-06-01 21:00 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/01/2017 03:20 AM, Marc Zyngier wrote:
> Some systems have less than perfect GICv3 implementations, leading to
> all kind of ugly issues (guest hanging, host dying). In order to allow
> some level of diagnostic, and in some cases implement workarounds,
> this series enables the trapping of both Group-0, Group-1 and Common
> sysregs. Mediating the access at EL2 allows some form of sanity
> checking that the HW is sometimes sorely lacking.
> 
> Instead of fully emulating a GICv3 CPU interface, we still use the
> existing HW (list registers, AP registers, VMCR...), which allows the
> code to be independent from the rest of the KVM code, and to cope with
> partial trapping.
> 
> Of course, trapping has a cost, which is why this must be either
> enabled on the command line, or selected by another cpu capability
> (see Cavium erratum 30115). A quick test on an A57-based platform
> shows a 25% hit when repeatedly banging on the trapped registers,
> while normal workloads do not seem to suffer noticeably from such
> trapping (hackbench variance is in the usual noise, despite being very
> IPI happy).
> 
> This has been tested on a dual socket Thundex-X and a Freescale LS-2085a.
> 
> I've taken the liberty to rebase David Daney's initial Cavium erratum
> 30115 workaround on top of this series, and included it here as a
> typical use case.

I pulled this from:

 
https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git/log/?h=kvm-arm64/gicv3-cpuif-mediated-access

this morning at commit	58c1763c5aa6223ab3d04e0c183a31eb0aef832e

Entire series tested by and

Acked-by: David Daney <david.daney@cavium.com>

Thanks again.

> 
> - From v1:
>    * Fix bug in DIR handling which would have performed a deactivation even
>      when EOImode==0
>    * Some minor cleanups and clarifications.
>    * All the initial fixes have already been merged.
>    * Rebased on 4.12-rc3.
> 
> David Daney (2):
>    arm64: Add MIDR values for Cavium cn83XX SoCs
>    arm64: Add workaround for Cavium Thunder erratum 30115
> 
> Marc Zyngier (23):
>    arm64: Add a facility to turn an ESR syndrome into a sysreg encoding
>    KVM: arm/arm64: vgic-v3: Add accessors for the ICH_APxRn_EL2 registers
>    KVM: arm64: Make kvm_condition_valid32() accessible from EL2
>    KVM: arm64: vgic-v3: Add hook to handle guest GICv3 sysreg accesses at
>      EL2
>    KVM: arm64: vgic-v3: Add ICV_BPR1_EL1 handler
>    KVM: arm64: vgic-v3: Add ICV_IGRPEN1_EL1 handler
>    KVM: arm64: vgic-v3: Add ICV_IAR1_EL1 handler
>    KVM: arm64: vgic-v3: Add ICV_EOIR1_EL1 handler
>    KVM: arm64: vgic-v3: Add ICV_AP1Rn_EL1 handler
>    KVM: arm64: vgic-v3: Add ICV_HPPIR1_EL1 handler
>    KVM: arm64: vgic-v3: Enable trapping of Group-1 system registers
>    KVM: arm64: Enable GICv3 Group-1 sysreg trapping via command-line
>    KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler
>    KVM: arm64: vgic-v3: Add ICV_IGNREN0_EL1 handler
>    KVM: arm64: vgic-v3: Add misc Group-0 handlers
>    KVM: arm64: vgic-v3: Enable trapping of Group-0 system registers
>    KVM: arm64: Enable GICv3 Group-0 sysreg trapping via command-line
>    KVM: arm64: vgic-v3: Add ICV_DIR_EL1 handler
>    KVM: arm64: vgic-v3: Add ICV_RPR_EL1 handler
>    KVM: arm64: vgic-v3: Add ICV_CTLR_EL1 handler
>    KVM: arm64: vgic-v3: Add ICV_PMR_EL1 handler
>    KVM: arm64: Enable GICv3 common sysreg trapping via command-line
>    KVM: arm64: vgic-v3: Log which GICv3 system registers are trapped
> 
>   Documentation/arm64/silicon-errata.txt |   1 +
>   arch/arm64/Kconfig                     |  11 +
>   arch/arm64/include/asm/cpucaps.h       |   3 +-
>   arch/arm64/include/asm/cputype.h       |   2 +
>   arch/arm64/include/asm/esr.h           |  24 +
>   arch/arm64/include/asm/kvm_hyp.h       |   1 +
>   arch/arm64/include/asm/sysreg.h        |   9 +
>   arch/arm64/kernel/cpu_errata.c         |  21 +
>   arch/arm64/kvm/hyp/switch.c            |  14 +
>   include/kvm/arm_vgic.h                 |   1 +
>   include/linux/irqchip/arm-gic-v3.h     |   6 +
>   virt/kvm/arm/aarch32.c                 |   2 +-
>   virt/kvm/arm/hyp/vgic-v3-sr.c          | 803 ++++++++++++++++++++++++++++++++-
>   virt/kvm/arm/vgic/vgic-v3.c            |  45 ++
>   14 files changed, 925 insertions(+), 18 deletions(-)
> 

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

* Re: [PATCH v2 00/25] arm64: KVM: Mediate access to GICv3 sysregs at EL2
  2017-06-01 21:00   ` David Daney
@ 2017-06-02  9:11     ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-02  9:11 UTC (permalink / raw)
  To: David Daney, Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter, kvmarm,
	linux-arm-kernel

On 01/06/17 22:00, David Daney wrote:
> On 06/01/2017 03:20 AM, Marc Zyngier wrote:
>> Some systems have less than perfect GICv3 implementations, leading to
>> all kind of ugly issues (guest hanging, host dying). In order to allow
>> some level of diagnostic, and in some cases implement workarounds,
>> this series enables the trapping of both Group-0, Group-1 and Common
>> sysregs. Mediating the access at EL2 allows some form of sanity
>> checking that the HW is sometimes sorely lacking.
>>
>> Instead of fully emulating a GICv3 CPU interface, we still use the
>> existing HW (list registers, AP registers, VMCR...), which allows the
>> code to be independent from the rest of the KVM code, and to cope with
>> partial trapping.
>>
>> Of course, trapping has a cost, which is why this must be either
>> enabled on the command line, or selected by another cpu capability
>> (see Cavium erratum 30115). A quick test on an A57-based platform
>> shows a 25% hit when repeatedly banging on the trapped registers,
>> while normal workloads do not seem to suffer noticeably from such
>> trapping (hackbench variance is in the usual noise, despite being very
>> IPI happy).
>>
>> This has been tested on a dual socket Thundex-X and a Freescale LS-2085a.
>>
>> I've taken the liberty to rebase David Daney's initial Cavium erratum
>> 30115 workaround on top of this series, and included it here as a
>> typical use case.
> 
> I pulled this from:
> 
>  
> https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git/log/?h=kvm-arm64/gicv3-cpuif-mediated-access
> 
> this morning at commit	58c1763c5aa6223ab3d04e0c183a31eb0aef832e
> 
> Entire series tested by and
> 
> Acked-by: David Daney <david.daney@cavium.com>

Thanks David. May I ask what particular system this was tested on (just
so that I have a additional reference point)?

Cheers,

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

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

* [PATCH v2 00/25] arm64: KVM: Mediate access to GICv3 sysregs at EL2
@ 2017-06-02  9:11     ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-02  9:11 UTC (permalink / raw)
  To: linux-arm-kernel

On 01/06/17 22:00, David Daney wrote:
> On 06/01/2017 03:20 AM, Marc Zyngier wrote:
>> Some systems have less than perfect GICv3 implementations, leading to
>> all kind of ugly issues (guest hanging, host dying). In order to allow
>> some level of diagnostic, and in some cases implement workarounds,
>> this series enables the trapping of both Group-0, Group-1 and Common
>> sysregs. Mediating the access at EL2 allows some form of sanity
>> checking that the HW is sometimes sorely lacking.
>>
>> Instead of fully emulating a GICv3 CPU interface, we still use the
>> existing HW (list registers, AP registers, VMCR...), which allows the
>> code to be independent from the rest of the KVM code, and to cope with
>> partial trapping.
>>
>> Of course, trapping has a cost, which is why this must be either
>> enabled on the command line, or selected by another cpu capability
>> (see Cavium erratum 30115). A quick test on an A57-based platform
>> shows a 25% hit when repeatedly banging on the trapped registers,
>> while normal workloads do not seem to suffer noticeably from such
>> trapping (hackbench variance is in the usual noise, despite being very
>> IPI happy).
>>
>> This has been tested on a dual socket Thundex-X and a Freescale LS-2085a.
>>
>> I've taken the liberty to rebase David Daney's initial Cavium erratum
>> 30115 workaround on top of this series, and included it here as a
>> typical use case.
> 
> I pulled this from:
> 
>  
> https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git/log/?h=kvm-arm64/gicv3-cpuif-mediated-access
> 
> this morning at commit	58c1763c5aa6223ab3d04e0c183a31eb0aef832e
> 
> Entire series tested by and
> 
> Acked-by: David Daney <david.daney@cavium.com>

Thanks David. May I ask what particular system this was tested on (just
so that I have a additional reference point)?

Cheers,

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

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

* Re: [PATCH v2 00/25] arm64: KVM: Mediate access to GICv3 sysregs at EL2
  2017-06-02  9:11     ` Marc Zyngier
@ 2017-06-02 16:24       ` David Daney
  -1 siblings, 0 replies; 152+ messages in thread
From: David Daney @ 2017-06-02 16:24 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall
  Cc: David Daney, Catalin Marinas, Mark Rutland, Robert Richter,
	Eric Auger, kvmarm, linux-arm-kernel, kvm

On 06/02/2017 02:11 AM, Marc Zyngier wrote:
> On 01/06/17 22:00, David Daney wrote:
>> On 06/01/2017 03:20 AM, Marc Zyngier wrote:
>>> Some systems have less than perfect GICv3 implementations, leading to
>>> all kind of ugly issues (guest hanging, host dying). In order to allow
>>> some level of diagnostic, and in some cases implement workarounds,
>>> this series enables the trapping of both Group-0, Group-1 and Common
>>> sysregs. Mediating the access at EL2 allows some form of sanity
>>> checking that the HW is sometimes sorely lacking.
>>>
>>> Instead of fully emulating a GICv3 CPU interface, we still use the
>>> existing HW (list registers, AP registers, VMCR...), which allows the
>>> code to be independent from the rest of the KVM code, and to cope with
>>> partial trapping.
>>>
>>> Of course, trapping has a cost, which is why this must be either
>>> enabled on the command line, or selected by another cpu capability
>>> (see Cavium erratum 30115). A quick test on an A57-based platform
>>> shows a 25% hit when repeatedly banging on the trapped registers,
>>> while normal workloads do not seem to suffer noticeably from such
>>> trapping (hackbench variance is in the usual noise, despite being very
>>> IPI happy).
>>>
>>> This has been tested on a dual socket Thundex-X and a Freescale LS-2085a.
>>>
>>> I've taken the liberty to rebase David Daney's initial Cavium erratum
>>> 30115 workaround on top of this series, and included it here as a
>>> typical use case.
>>
>> I pulled this from:
>>
>>   
>> https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git/log/?h=kvm-arm64/gicv3-cpuif-mediated-access
>>
>> this morning at commit	58c1763c5aa6223ab3d04e0c183a31eb0aef832e
>>
>> Entire series tested by and
>>
>> Acked-by: David Daney <david.daney@cavium.com>
> 
> Thanks David. May I ask what particular system this was tested on (just
> so that I have a additional reference point)?

Sure, Unfortunatly I think it doesn't really increase your testing coverage.

I tested on a 2-node NUMA Cavium cn8890 (ThunderX).  This chassis is 
known as CRB-2S.  Running Ubuntu 16.04.2 userspace.

First I verified that a kernel built from clean v4.12-rc3 would fail 
with symptoms of no interrupts being processed while running a heavy KVM 
start/stop workload.  It does, we get a failure in under 5 minutes.

Then I applied your 25 patch set, and retested.  With the patch set 
applied, no failures were observed after more than 4 hours.


> 
> Cheers,
> 
> 	M.
> 

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

* [PATCH v2 00/25] arm64: KVM: Mediate access to GICv3 sysregs at EL2
@ 2017-06-02 16:24       ` David Daney
  0 siblings, 0 replies; 152+ messages in thread
From: David Daney @ 2017-06-02 16:24 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/02/2017 02:11 AM, Marc Zyngier wrote:
> On 01/06/17 22:00, David Daney wrote:
>> On 06/01/2017 03:20 AM, Marc Zyngier wrote:
>>> Some systems have less than perfect GICv3 implementations, leading to
>>> all kind of ugly issues (guest hanging, host dying). In order to allow
>>> some level of diagnostic, and in some cases implement workarounds,
>>> this series enables the trapping of both Group-0, Group-1 and Common
>>> sysregs. Mediating the access at EL2 allows some form of sanity
>>> checking that the HW is sometimes sorely lacking.
>>>
>>> Instead of fully emulating a GICv3 CPU interface, we still use the
>>> existing HW (list registers, AP registers, VMCR...), which allows the
>>> code to be independent from the rest of the KVM code, and to cope with
>>> partial trapping.
>>>
>>> Of course, trapping has a cost, which is why this must be either
>>> enabled on the command line, or selected by another cpu capability
>>> (see Cavium erratum 30115). A quick test on an A57-based platform
>>> shows a 25% hit when repeatedly banging on the trapped registers,
>>> while normal workloads do not seem to suffer noticeably from such
>>> trapping (hackbench variance is in the usual noise, despite being very
>>> IPI happy).
>>>
>>> This has been tested on a dual socket Thundex-X and a Freescale LS-2085a.
>>>
>>> I've taken the liberty to rebase David Daney's initial Cavium erratum
>>> 30115 workaround on top of this series, and included it here as a
>>> typical use case.
>>
>> I pulled this from:
>>
>>   
>> https://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git/log/?h=kvm-arm64/gicv3-cpuif-mediated-access
>>
>> this morning at commit	58c1763c5aa6223ab3d04e0c183a31eb0aef832e
>>
>> Entire series tested by and
>>
>> Acked-by: David Daney <david.daney@cavium.com>
> 
> Thanks David. May I ask what particular system this was tested on (just
> so that I have a additional reference point)?

Sure, Unfortunatly I think it doesn't really increase your testing coverage.

I tested on a 2-node NUMA Cavium cn8890 (ThunderX).  This chassis is 
known as CRB-2S.  Running Ubuntu 16.04.2 userspace.

First I verified that a kernel built from clean v4.12-rc3 would fail 
with symptoms of no interrupts being processed while running a heavy KVM 
start/stop workload.  It does, we get a failure in under 5 minutes.

Then I applied your 25 patch set, and retested.  With the patch set 
applied, no failures were observed after more than 4 hours.


> 
> Cheers,
> 
> 	M.
> 

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

* Re: [PATCH v2 03/25] KVM: arm64: Make kvm_condition_valid32() accessible from EL2
  2017-06-01 10:20   ` Marc Zyngier
@ 2017-06-04 12:11     ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-04 12:11 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On Thu, Jun 01, 2017 at 11:20:55AM +0100, Marc Zyngier wrote:
> As we're about to trap CP15 accesses and handle them at EL2, we
> need to evaluate whether or not the condition flags are valid,
> as an implementation is allowed to trap despite the condition
> not being met.
> 
> Tagging the function as __hyp_text allows this.

is the cc_map also guaranteed to work (by simple reference) in EL2 then?


Thanks,
-Christoffer

> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  virt/kvm/arm/aarch32.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/aarch32.c b/virt/kvm/arm/aarch32.c
> index 528af4b2d09e..79c7c357804b 100644
> --- a/virt/kvm/arm/aarch32.c
> +++ b/virt/kvm/arm/aarch32.c
> @@ -60,7 +60,7 @@ static const unsigned short cc_map[16] = {
>  /*
>   * Check if a trapped instruction should have been executed or not.
>   */
> -bool kvm_condition_valid32(const struct kvm_vcpu *vcpu)
> +bool __hyp_text kvm_condition_valid32(const struct kvm_vcpu *vcpu)
>  {
>  	unsigned long cpsr;
>  	u32 cpsr_cond;
> -- 
> 2.11.0
> 

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

* [PATCH v2 03/25] KVM: arm64: Make kvm_condition_valid32() accessible from EL2
@ 2017-06-04 12:11     ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-04 12:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 01, 2017 at 11:20:55AM +0100, Marc Zyngier wrote:
> As we're about to trap CP15 accesses and handle them at EL2, we
> need to evaluate whether or not the condition flags are valid,
> as an implementation is allowed to trap despite the condition
> not being met.
> 
> Tagging the function as __hyp_text allows this.

is the cc_map also guaranteed to work (by simple reference) in EL2 then?


Thanks,
-Christoffer

> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  virt/kvm/arm/aarch32.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/aarch32.c b/virt/kvm/arm/aarch32.c
> index 528af4b2d09e..79c7c357804b 100644
> --- a/virt/kvm/arm/aarch32.c
> +++ b/virt/kvm/arm/aarch32.c
> @@ -60,7 +60,7 @@ static const unsigned short cc_map[16] = {
>  /*
>   * Check if a trapped instruction should have been executed or not.
>   */
> -bool kvm_condition_valid32(const struct kvm_vcpu *vcpu)
> +bool __hyp_text kvm_condition_valid32(const struct kvm_vcpu *vcpu)
>  {
>  	unsigned long cpsr;
>  	u32 cpsr_cond;
> -- 
> 2.11.0
> 

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

* Re: [PATCH v2 04/25] KVM: arm64: vgic-v3: Add hook to handle guest GICv3 sysreg accesses at EL2
  2017-06-01 10:20   ` Marc Zyngier
@ 2017-06-04 14:59     ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-04 14:59 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter,
	linux-arm-kernel, kvmarm

On Thu, Jun 01, 2017 at 11:20:56AM +0100, Marc Zyngier wrote:
> In order to start handling guest access to GICv3 system registers,
> let's add a hook that will get called when we trap a system register
> access. This is gated by a new static key (vgic_v3_cpuif_trap).
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Reviewed-by: Christoffer Dall <cdall@linaro.org>

> ---
>  arch/arm64/include/asm/kvm_hyp.h |  1 +
>  arch/arm64/kvm/hyp/switch.c      | 14 ++++++++++++++
>  include/kvm/arm_vgic.h           |  1 +
>  virt/kvm/arm/hyp/vgic-v3-sr.c    | 38 ++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v3.c      |  2 ++
>  5 files changed, 56 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
> index b18e852d27e8..4572a9b560fa 100644
> --- a/arch/arm64/include/asm/kvm_hyp.h
> +++ b/arch/arm64/include/asm/kvm_hyp.h
> @@ -127,6 +127,7 @@ 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);
> +int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
>  
>  void __timer_save_state(struct kvm_vcpu *vcpu);
>  void __timer_restore_state(struct kvm_vcpu *vcpu);
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index aede1658aeda..dfd8ca16601b 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -350,6 +350,20 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
>  		}
>  	}
>  
> +	if (static_branch_unlikely(&vgic_v3_cpuif_trap) &&
> +	    exit_code == ARM_EXCEPTION_TRAP &&
> +	    (kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_SYS64 ||
> +	     kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_CP15_32)) {
> +		int ret = __vgic_v3_perform_cpuif_access(vcpu);
> +
> +		if (ret == 1) {
> +			__skip_instr(vcpu);
> +			goto again;
> +		}
> +
> +		/* 0 falls through to be handled out of EL2 */
> +	}
> +
>  	fp_enabled = __fpsimd_enabled();
>  
>  	__sysreg_save_guest_state(guest_ctxt);
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index ef718586321c..39b9fc4dc65d 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -285,6 +285,7 @@ struct vgic_cpu {
>  };
>  
>  extern struct static_key_false vgic_v2_cpuif_trap;
> +extern struct static_key_false vgic_v3_cpuif_trap;
>  
>  int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
>  void kvm_vgic_early_init(struct kvm *kvm);
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 990d9d1e85d0..943bf11252d9 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -19,6 +19,7 @@
>  #include <linux/irqchip/arm-gic-v3.h>
>  #include <linux/kvm_host.h>
>  
> +#include <asm/kvm_emulate.h>
>  #include <asm/kvm_hyp.h>
>  
>  #define vtr_to_max_lr_idx(v)		((v) & 0xf)
> @@ -371,3 +372,40 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
>  {
>  	write_gicreg(vmcr, ICH_VMCR_EL2);
>  }
> +
> +#ifdef CONFIG_ARM64
> +
> +int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
> +{
> +	int rt;
> +	u32 esr;
> +	u32 vmcr;
> +	void (*fn)(struct kvm_vcpu *, u32, int);
> +	bool is_read;
> +	u32 sysreg;
> +
> +	esr = kvm_vcpu_get_hsr(vcpu);
> +	if (vcpu_mode_is_32bit(vcpu)) {
> +		if (!kvm_condition_valid(vcpu))
> +			return 1;
> +
> +		sysreg = esr_cp15_to_sysreg(esr);
> +	} else {
> +		sysreg = esr_sys64_to_sysreg(esr);
> +	}
> +
> +	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
> +
> +	switch (sysreg) {
> +	default:
> +		return 0;
> +	}
> +
> +	vmcr = __vgic_v3_read_vmcr();
> +	rt = kvm_vcpu_sys_get_rt(vcpu);
> +	fn(vcpu, vmcr, rt);
> +
> +	return 1;
> +}
> +
> +#endif
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 6fe3f003636a..88d9bd9bf468 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -410,6 +410,8 @@ int vgic_v3_map_resources(struct kvm *kvm)
>  	return ret;
>  }
>  
> +DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap);
> +
>  /**
>   * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
>   * @node:	pointer to the DT node
> -- 
> 2.11.0
> 

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

* [PATCH v2 04/25] KVM: arm64: vgic-v3: Add hook to handle guest GICv3 sysreg accesses at EL2
@ 2017-06-04 14:59     ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-04 14:59 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 01, 2017 at 11:20:56AM +0100, Marc Zyngier wrote:
> In order to start handling guest access to GICv3 system registers,
> let's add a hook that will get called when we trap a system register
> access. This is gated by a new static key (vgic_v3_cpuif_trap).
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Reviewed-by: Christoffer Dall <cdall@linaro.org>

> ---
>  arch/arm64/include/asm/kvm_hyp.h |  1 +
>  arch/arm64/kvm/hyp/switch.c      | 14 ++++++++++++++
>  include/kvm/arm_vgic.h           |  1 +
>  virt/kvm/arm/hyp/vgic-v3-sr.c    | 38 ++++++++++++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v3.c      |  2 ++
>  5 files changed, 56 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
> index b18e852d27e8..4572a9b560fa 100644
> --- a/arch/arm64/include/asm/kvm_hyp.h
> +++ b/arch/arm64/include/asm/kvm_hyp.h
> @@ -127,6 +127,7 @@ 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);
> +int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu);
>  
>  void __timer_save_state(struct kvm_vcpu *vcpu);
>  void __timer_restore_state(struct kvm_vcpu *vcpu);
> diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
> index aede1658aeda..dfd8ca16601b 100644
> --- a/arch/arm64/kvm/hyp/switch.c
> +++ b/arch/arm64/kvm/hyp/switch.c
> @@ -350,6 +350,20 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
>  		}
>  	}
>  
> +	if (static_branch_unlikely(&vgic_v3_cpuif_trap) &&
> +	    exit_code == ARM_EXCEPTION_TRAP &&
> +	    (kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_SYS64 ||
> +	     kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_CP15_32)) {
> +		int ret = __vgic_v3_perform_cpuif_access(vcpu);
> +
> +		if (ret == 1) {
> +			__skip_instr(vcpu);
> +			goto again;
> +		}
> +
> +		/* 0 falls through to be handled out of EL2 */
> +	}
> +
>  	fp_enabled = __fpsimd_enabled();
>  
>  	__sysreg_save_guest_state(guest_ctxt);
> diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
> index ef718586321c..39b9fc4dc65d 100644
> --- a/include/kvm/arm_vgic.h
> +++ b/include/kvm/arm_vgic.h
> @@ -285,6 +285,7 @@ struct vgic_cpu {
>  };
>  
>  extern struct static_key_false vgic_v2_cpuif_trap;
> +extern struct static_key_false vgic_v3_cpuif_trap;
>  
>  int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
>  void kvm_vgic_early_init(struct kvm *kvm);
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 990d9d1e85d0..943bf11252d9 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -19,6 +19,7 @@
>  #include <linux/irqchip/arm-gic-v3.h>
>  #include <linux/kvm_host.h>
>  
> +#include <asm/kvm_emulate.h>
>  #include <asm/kvm_hyp.h>
>  
>  #define vtr_to_max_lr_idx(v)		((v) & 0xf)
> @@ -371,3 +372,40 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
>  {
>  	write_gicreg(vmcr, ICH_VMCR_EL2);
>  }
> +
> +#ifdef CONFIG_ARM64
> +
> +int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
> +{
> +	int rt;
> +	u32 esr;
> +	u32 vmcr;
> +	void (*fn)(struct kvm_vcpu *, u32, int);
> +	bool is_read;
> +	u32 sysreg;
> +
> +	esr = kvm_vcpu_get_hsr(vcpu);
> +	if (vcpu_mode_is_32bit(vcpu)) {
> +		if (!kvm_condition_valid(vcpu))
> +			return 1;
> +
> +		sysreg = esr_cp15_to_sysreg(esr);
> +	} else {
> +		sysreg = esr_sys64_to_sysreg(esr);
> +	}
> +
> +	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
> +
> +	switch (sysreg) {
> +	default:
> +		return 0;
> +	}
> +
> +	vmcr = __vgic_v3_read_vmcr();
> +	rt = kvm_vcpu_sys_get_rt(vcpu);
> +	fn(vcpu, vmcr, rt);
> +
> +	return 1;
> +}
> +
> +#endif
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 6fe3f003636a..88d9bd9bf468 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -410,6 +410,8 @@ int vgic_v3_map_resources(struct kvm *kvm)
>  	return ret;
>  }
>  
> +DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap);
> +
>  /**
>   * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
>   * @node:	pointer to the DT node
> -- 
> 2.11.0
> 

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

* Re: [PATCH v2 05/25] KVM: arm64: vgic-v3: Add ICV_BPR1_EL1 handler
  2017-06-01 10:20   ` Marc Zyngier
@ 2017-06-04 20:25     ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-04 20:25 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter,
	linux-arm-kernel, kvmarm

On Thu, Jun 01, 2017 at 11:20:57AM +0100, Marc Zyngier wrote:
> Add a handler for reading/writing the guest's view of the ICC_BPR1_EL1
> register, which is located in the ICH_VMCR_EL2.BPR1 field.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  virt/kvm/arm/hyp/vgic-v3-sr.c | 51 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 51 insertions(+)
> 
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 943bf11252d9..6254eaf72a77 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -375,6 +375,51 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
>  
>  #ifdef CONFIG_ARM64
>  
> +static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
> +{
> +	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
> +}
> +
> +static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
> +{
> +	unsigned int bpr;
> +
> +	if (vmcr & ICH_VMCR_CBPR_MASK) {
> +		bpr = __vgic_v3_get_bpr0(vmcr);
> +		if (bpr < 7)
> +			bpr++;
> +	} else {
> +		bpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
> +	}
> +
> +	return bpr;
> +}
> +
> +static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> +{
> +	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
> +}
> +
> +static void __hyp_text __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> +{
> +	u64 val = vcpu_get_reg(vcpu, rt);
> +	u8 bpr_min = 8 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));

I can't seem to find where this behavior is documented, is it that 8 is
the theoretical max, and it's the upper preemption levels that apply, so
it must be 8 - number supported?

> +
> +	if (vmcr & ICH_VMCR_CBPR_MASK)
> +		return;
> +
> +	/* Enforce BPR limiting */
> +	if (val < bpr_min)
> +		val = bpr_min;

Are we not implying that the reset value here also means bpr_min?  I
also can't seem to find this behavior in the spec and it appears we rely
on the underlying hardware to set a reset value (by setting vmcr=0 on
first run).  Could this result in a guest observing one reset value,
writing 0 to this register, and observing another one?

> +
> +	val <<= ICH_VMCR_BPR1_SHIFT;
> +	val &= ICH_VMCR_BPR1_MASK;
> +	vmcr &= ~ICH_VMCR_BPR1_MASK;
> +	vmcr |= val;
> +
> +	__vgic_v3_write_vmcr(vmcr);
> +}
> +
>  int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  {
>  	int rt;
> @@ -397,6 +442,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
>  
>  	switch (sysreg) {
> +	case SYS_ICC_BPR1_EL1:
> +		if (is_read)
> +			fn = __vgic_v3_read_bpr1;
> +		else
> +			fn = __vgic_v3_write_bpr1;
> +		break;

Did you consider a lookup table with the sysreg encoding, the read
function, and the right function as each entry?  It may compress the
code a bit, but I'm not sure if it's nicer or worth it.

>  	default:
>  		return 0;
>  	}
> -- 
> 2.11.0
> 

Thanks,
-Christoffer

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

* [PATCH v2 05/25] KVM: arm64: vgic-v3: Add ICV_BPR1_EL1 handler
@ 2017-06-04 20:25     ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-04 20:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 01, 2017 at 11:20:57AM +0100, Marc Zyngier wrote:
> Add a handler for reading/writing the guest's view of the ICC_BPR1_EL1
> register, which is located in the ICH_VMCR_EL2.BPR1 field.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  virt/kvm/arm/hyp/vgic-v3-sr.c | 51 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 51 insertions(+)
> 
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 943bf11252d9..6254eaf72a77 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -375,6 +375,51 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
>  
>  #ifdef CONFIG_ARM64
>  
> +static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
> +{
> +	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
> +}
> +
> +static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
> +{
> +	unsigned int bpr;
> +
> +	if (vmcr & ICH_VMCR_CBPR_MASK) {
> +		bpr = __vgic_v3_get_bpr0(vmcr);
> +		if (bpr < 7)
> +			bpr++;
> +	} else {
> +		bpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
> +	}
> +
> +	return bpr;
> +}
> +
> +static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> +{
> +	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
> +}
> +
> +static void __hyp_text __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> +{
> +	u64 val = vcpu_get_reg(vcpu, rt);
> +	u8 bpr_min = 8 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));

I can't seem to find where this behavior is documented, is it that 8 is
the theoretical max, and it's the upper preemption levels that apply, so
it must be 8 - number supported?

> +
> +	if (vmcr & ICH_VMCR_CBPR_MASK)
> +		return;
> +
> +	/* Enforce BPR limiting */
> +	if (val < bpr_min)
> +		val = bpr_min;

Are we not implying that the reset value here also means bpr_min?  I
also can't seem to find this behavior in the spec and it appears we rely
on the underlying hardware to set a reset value (by setting vmcr=0 on
first run).  Could this result in a guest observing one reset value,
writing 0 to this register, and observing another one?

> +
> +	val <<= ICH_VMCR_BPR1_SHIFT;
> +	val &= ICH_VMCR_BPR1_MASK;
> +	vmcr &= ~ICH_VMCR_BPR1_MASK;
> +	vmcr |= val;
> +
> +	__vgic_v3_write_vmcr(vmcr);
> +}
> +
>  int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  {
>  	int rt;
> @@ -397,6 +442,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
>  
>  	switch (sysreg) {
> +	case SYS_ICC_BPR1_EL1:
> +		if (is_read)
> +			fn = __vgic_v3_read_bpr1;
> +		else
> +			fn = __vgic_v3_write_bpr1;
> +		break;

Did you consider a lookup table with the sysreg encoding, the read
function, and the right function as each entry?  It may compress the
code a bit, but I'm not sure if it's nicer or worth it.

>  	default:
>  		return 0;
>  	}
> -- 
> 2.11.0
> 

Thanks,
-Christoffer

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

* Re: [PATCH v2 03/25] KVM: arm64: Make kvm_condition_valid32() accessible from EL2
  2017-06-04 12:11     ` Christoffer Dall
@ 2017-06-05  8:13       ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-05  8:13 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On 04/06/17 13:11, Christoffer Dall wrote:
> On Thu, Jun 01, 2017 at 11:20:55AM +0100, Marc Zyngier wrote:
>> As we're about to trap CP15 accesses and handle them at EL2, we
>> need to evaluate whether or not the condition flags are valid,
>> as an implementation is allowed to trap despite the condition
>> not being met.
>>
>> Tagging the function as __hyp_text allows this.
> 
> is the cc_map also guaranteed to work (by simple reference) in EL2 then?

Yes. By virtue of being const, this ends up in the read-only part of the
kernel, which we always map at EL2.

Thanks,

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

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

* [PATCH v2 03/25] KVM: arm64: Make kvm_condition_valid32() accessible from EL2
@ 2017-06-05  8:13       ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-05  8:13 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/06/17 13:11, Christoffer Dall wrote:
> On Thu, Jun 01, 2017 at 11:20:55AM +0100, Marc Zyngier wrote:
>> As we're about to trap CP15 accesses and handle them at EL2, we
>> need to evaluate whether or not the condition flags are valid,
>> as an implementation is allowed to trap despite the condition
>> not being met.
>>
>> Tagging the function as __hyp_text allows this.
> 
> is the cc_map also guaranteed to work (by simple reference) in EL2 then?

Yes. By virtue of being const, this ends up in the read-only part of the
kernel, which we always map at EL2.

Thanks,

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

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

* Re: [PATCH v2 03/25] KVM: arm64: Make kvm_condition_valid32() accessible from EL2
  2017-06-05  8:13       ` Marc Zyngier
@ 2017-06-05  8:23         ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-05  8:23 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter,
	linux-arm-kernel, kvmarm

On Mon, Jun 05, 2017 at 09:13:53AM +0100, Marc Zyngier wrote:
> On 04/06/17 13:11, Christoffer Dall wrote:
> > On Thu, Jun 01, 2017 at 11:20:55AM +0100, Marc Zyngier wrote:
> >> As we're about to trap CP15 accesses and handle them at EL2, we
> >> need to evaluate whether or not the condition flags are valid,
> >> as an implementation is allowed to trap despite the condition
> >> not being met.
> >>
> >> Tagging the function as __hyp_text allows this.
> > 
> > is the cc_map also guaranteed to work (by simple reference) in EL2 then?
> 
> Yes. By virtue of being const, this ends up in the read-only part of the
> kernel, which we always map at EL2.
> 

And why don't we have to do any address-translation-to-hyp tricks on the
address?  Are we guaranteed that it's a relative address and everything
is relocated with the same offset, or how was that again?

Thanks,
-Christoffer

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

* [PATCH v2 03/25] KVM: arm64: Make kvm_condition_valid32() accessible from EL2
@ 2017-06-05  8:23         ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-05  8:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jun 05, 2017 at 09:13:53AM +0100, Marc Zyngier wrote:
> On 04/06/17 13:11, Christoffer Dall wrote:
> > On Thu, Jun 01, 2017 at 11:20:55AM +0100, Marc Zyngier wrote:
> >> As we're about to trap CP15 accesses and handle them at EL2, we
> >> need to evaluate whether or not the condition flags are valid,
> >> as an implementation is allowed to trap despite the condition
> >> not being met.
> >>
> >> Tagging the function as __hyp_text allows this.
> > 
> > is the cc_map also guaranteed to work (by simple reference) in EL2 then?
> 
> Yes. By virtue of being const, this ends up in the read-only part of the
> kernel, which we always map at EL2.
> 

And why don't we have to do any address-translation-to-hyp tricks on the
address?  Are we guaranteed that it's a relative address and everything
is relocated with the same offset, or how was that again?

Thanks,
-Christoffer

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

* Re: [PATCH v2 03/25] KVM: arm64: Make kvm_condition_valid32() accessible from EL2
  2017-06-05  8:23         ` Christoffer Dall
@ 2017-06-05  9:10           ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-05  9:10 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter,
	linux-arm-kernel, kvmarm

On 05/06/17 09:23, Christoffer Dall wrote:
> On Mon, Jun 05, 2017 at 09:13:53AM +0100, Marc Zyngier wrote:
>> On 04/06/17 13:11, Christoffer Dall wrote:
>>> On Thu, Jun 01, 2017 at 11:20:55AM +0100, Marc Zyngier wrote:
>>>> As we're about to trap CP15 accesses and handle them at EL2, we
>>>> need to evaluate whether or not the condition flags are valid,
>>>> as an implementation is allowed to trap despite the condition
>>>> not being met.
>>>>
>>>> Tagging the function as __hyp_text allows this.
>>>
>>> is the cc_map also guaranteed to work (by simple reference) in EL2 then?
>>
>> Yes. By virtue of being const, this ends up in the read-only part of the
>> kernel, which we always map at EL2.
>>
> 
> And why don't we have to do any address-translation-to-hyp tricks on the
> address?  Are we guaranteed that it's a relative address and everything
> is relocated with the same offset, or how was that again?

Arghh, I completely missed this. Yeah, it works because this is a single
compilation unit, that the array is static, used only once, and that the
compiler is using relative addressing and not playing any dirty tricks
on us.

We could make the whole thing private to kvm_condition_valid32, but
that's not more of a guarantee that things won't break if the compiler
decides to generate absolute addresses.

Thanks,

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

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

* [PATCH v2 03/25] KVM: arm64: Make kvm_condition_valid32() accessible from EL2
@ 2017-06-05  9:10           ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-05  9:10 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/06/17 09:23, Christoffer Dall wrote:
> On Mon, Jun 05, 2017 at 09:13:53AM +0100, Marc Zyngier wrote:
>> On 04/06/17 13:11, Christoffer Dall wrote:
>>> On Thu, Jun 01, 2017 at 11:20:55AM +0100, Marc Zyngier wrote:
>>>> As we're about to trap CP15 accesses and handle them at EL2, we
>>>> need to evaluate whether or not the condition flags are valid,
>>>> as an implementation is allowed to trap despite the condition
>>>> not being met.
>>>>
>>>> Tagging the function as __hyp_text allows this.
>>>
>>> is the cc_map also guaranteed to work (by simple reference) in EL2 then?
>>
>> Yes. By virtue of being const, this ends up in the read-only part of the
>> kernel, which we always map at EL2.
>>
> 
> And why don't we have to do any address-translation-to-hyp tricks on the
> address?  Are we guaranteed that it's a relative address and everything
> is relocated with the same offset, or how was that again?

Arghh, I completely missed this. Yeah, it works because this is a single
compilation unit, that the array is static, used only once, and that the
compiler is using relative addressing and not playing any dirty tricks
on us.

We could make the whole thing private to kvm_condition_valid32, but
that's not more of a guarantee that things won't break if the compiler
decides to generate absolute addresses.

Thanks,

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

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

* Re: [PATCH v2 07/25] KVM: arm64: vgic-v3: Add ICV_IAR1_EL1 handler
  2017-06-01 10:20   ` Marc Zyngier
@ 2017-06-05  9:21     ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-05  9:21 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter,
	linux-arm-kernel, kvmarm

On Thu, Jun 01, 2017 at 11:20:59AM +0100, Marc Zyngier wrote:
> Add a handler for reading the guest's view of the ICC_IAR1_EL1
> register. This involves finding the highest priority Group-1
> interrupt, checking against both PMR and the active group
> priority, activating the interrupt and setting the group
> priority as active.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  include/linux/irqchip/arm-gic-v3.h |   1 +
>  virt/kvm/arm/hyp/vgic-v3-sr.c      | 150 +++++++++++++++++++++++++++++++++++++
>  2 files changed, 151 insertions(+)
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index fffb91202bc9..401db585a534 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -405,6 +405,7 @@
>  #define ICH_LR_PHYS_ID_SHIFT		32
>  #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
>  #define ICH_LR_PRIORITY_SHIFT		48
> +#define ICH_LR_PRIORITY_MASK		(0xffULL << ICH_LR_PRIORITY_SHIFT)
>  
>  /* These are for GICv2 emulation only */
>  #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 168539dfd0b9..16a2eadc7a5c 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -24,6 +24,7 @@
>  
>  #define vtr_to_max_lr_idx(v)		((v) & 0xf)
>  #define vtr_to_nr_pre_bits(v)		(((u32)(v) >> 26) + 1)
> +#define vtr_to_nr_apr_regs(v)		(1 << (vtr_to_nr_pre_bits(v) - 5))
>  
>  static u64 __hyp_text __gic_v3_get_lr(unsigned int lr)
>  {
> @@ -375,6 +376,79 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
>  
>  #ifdef CONFIG_ARM64
>  
> +static int __hyp_text __vgic_v3_get_group(struct kvm_vcpu *vcpu)
> +{
> +	u32 esr = kvm_vcpu_get_hsr(vcpu);
> +	u8 crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT;
> +
> +	return crm != 8;
> +}
> +
> +#define GICv3_IDLE_PRIORITY	0xff
> +
> +static int __hyp_text __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu,
> +						    u32 vmcr,
> +						    u64 *lr_val)
> +{
> +	unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
> +	u8 priority = GICv3_IDLE_PRIORITY;
> +	int i, lr = -1;
> +
> +	for (i = 0; i < used_lrs; i++) {
> +		u64 val = __gic_v3_get_lr(i);
> +		u8 lr_prio = (val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
> +
> +		/* Not pending in the state? */
> +		if ((val & ICH_LR_STATE) != ICH_LR_PENDING_BIT)
> +			continue;
> +
> +		/* Group-0 interrupt, but Group-0 disabled? */
> +		if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG0_MASK))
> +			continue;
> +
> +		/* Group-1 interrupt, but Group-1 disabled? */
> +		if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG1_MASK))
> +			continue;
> +
> +		/* Not the highest priority? */
> +		if (lr_prio >= priority)
> +			continue;
> +
> +		/* This is a candidate */
> +		priority = lr_prio;
> +		*lr_val = val;
> +		lr = i;
> +	}
> +
> +	if (lr == -1)
> +		*lr_val = ICC_IAR1_EL1_SPURIOUS;
> +
> +	return lr;
> +}
> +
> +static int __hyp_text __vgic_v3_get_highest_active_priority(void)
> +{
> +	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> +	u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
> +	u32 hap = 0;
> +	int i;
> +
> +	for (i = 0; i < nr_apr_regs; i++) {
> +		u32 val;
> +
> +		val  = __vgic_v3_read_ap0rn(i);
> +		val |= __vgic_v3_read_ap1rn(i);
> +		if (!val) {
> +			hap += 32;
> +			continue;
> +		}
> +
> +		return (hap + __ffs(val)) << (8 - nr_pre_bits);

I don't understand this shift, and I think I asked about it before, so
maybe if it's a reused concept we can use a static inline or at least
provide a comment?

> +	}
> +
> +	return GICv3_IDLE_PRIORITY;
> +}
> +
>  static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
>  {
>  	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
> @@ -395,6 +469,79 @@ static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
>  	return bpr;
>  }
>  
> +/*
> + * Convert a priority to a preemption level, taking the relevant BPR
> + * into account by zeroing the sub-priority bits.
> + */
> +static u8 __hyp_text __vgic_v3_pri_to_pre(u8 pri, u32 vmcr, int grp)
> +{
> +	unsigned int bpr;
> +
> +	if (!grp)
> +		bpr = __vgic_v3_get_bpr0(vmcr) + 1;
> +	else
> +		bpr = __vgic_v3_get_bpr1(vmcr);
> +
> +	return pri & (GENMASK(7, 0) << bpr);
> +}
> +
> +/*
> + * The priority value is independent of any of the BPR values, so we
> + * normalize it using nr_pre_bits. This guarantees that no matter what
> + * the guest does with its BPR, we can always set/get the same value
> + * of a priority.
> + */
> +static void __hyp_text __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp)
> +{
> +	u8 nr_pre_bits, pre, ap;
> +	u32 val;
> +	int apr;
> +
> +	nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> +	pre = __vgic_v3_pri_to_pre(pri, vmcr, grp);
> +	ap = pre >> (8 - nr_pre_bits);

Again here, I don't get this shift.

> +	apr = ap / 32;
> +
> +	val = __vgic_v3_read_ap1rn(apr);
> +	__vgic_v3_write_ap1rn(val | BIT(ap % 32), apr);

How are we sure this is a group 1 interrupt here?

> +}
> +
> +static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> +{
> +	u64 lr_val;
> +	u8 lr_prio, pmr;
> +	int lr, grp;
> +
> +	grp = __vgic_v3_get_group(vcpu);
> +
> +	lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
> +	if (lr < 0)
> +		goto spurious;
> +
> +	if (grp != !!(lr_val & ICH_LR_GROUP))
> +		goto spurious;
> +
> +	pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
> +	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
> +	if (pmr <= lr_prio)
> +		goto spurious;
> +
> +	if (__vgic_v3_get_highest_active_priority() <= lr_prio)
> +		goto spurious;
> +
> +	lr_val &= ~ICH_LR_STATE;
> +	/* No active state for LPIs */
> +	if ((lr_val & ICH_LR_VIRTUAL_ID_MASK) <= VGIC_MAX_SPI)
> +		lr_val |= ICH_LR_ACTIVE_BIT;
> +	__gic_v3_set_lr(lr_val, lr);
> +	__vgic_v3_set_active_priority(lr_prio, vmcr, grp);
> +	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
> +	return;
> +
> +spurious:
> +	vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS);
> +}
> +
>  static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  {
>  	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
> @@ -459,6 +606,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
>  
>  	switch (sysreg) {
> +	case SYS_ICC_IAR1_EL1:
> +		fn = __vgic_v3_read_iar;
> +		break;

So we don't provide a write-ignore function here because we rely on the
hardware to always trap that at EL1 instead?

I remember we discussed this before, but I don't remember if the
conclusion was that this is 100% safe.


>  	case SYS_ICC_GRPEN1_EL1:
>  		if (is_read)
>  			fn = __vgic_v3_read_igrpen1;
> -- 
> 2.11.0
> 

Thanks,
-Christoffer

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

* [PATCH v2 07/25] KVM: arm64: vgic-v3: Add ICV_IAR1_EL1 handler
@ 2017-06-05  9:21     ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-05  9:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 01, 2017 at 11:20:59AM +0100, Marc Zyngier wrote:
> Add a handler for reading the guest's view of the ICC_IAR1_EL1
> register. This involves finding the highest priority Group-1
> interrupt, checking against both PMR and the active group
> priority, activating the interrupt and setting the group
> priority as active.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  include/linux/irqchip/arm-gic-v3.h |   1 +
>  virt/kvm/arm/hyp/vgic-v3-sr.c      | 150 +++++++++++++++++++++++++++++++++++++
>  2 files changed, 151 insertions(+)
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index fffb91202bc9..401db585a534 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -405,6 +405,7 @@
>  #define ICH_LR_PHYS_ID_SHIFT		32
>  #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
>  #define ICH_LR_PRIORITY_SHIFT		48
> +#define ICH_LR_PRIORITY_MASK		(0xffULL << ICH_LR_PRIORITY_SHIFT)
>  
>  /* These are for GICv2 emulation only */
>  #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 168539dfd0b9..16a2eadc7a5c 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -24,6 +24,7 @@
>  
>  #define vtr_to_max_lr_idx(v)		((v) & 0xf)
>  #define vtr_to_nr_pre_bits(v)		(((u32)(v) >> 26) + 1)
> +#define vtr_to_nr_apr_regs(v)		(1 << (vtr_to_nr_pre_bits(v) - 5))
>  
>  static u64 __hyp_text __gic_v3_get_lr(unsigned int lr)
>  {
> @@ -375,6 +376,79 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
>  
>  #ifdef CONFIG_ARM64
>  
> +static int __hyp_text __vgic_v3_get_group(struct kvm_vcpu *vcpu)
> +{
> +	u32 esr = kvm_vcpu_get_hsr(vcpu);
> +	u8 crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT;
> +
> +	return crm != 8;
> +}
> +
> +#define GICv3_IDLE_PRIORITY	0xff
> +
> +static int __hyp_text __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu,
> +						    u32 vmcr,
> +						    u64 *lr_val)
> +{
> +	unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
> +	u8 priority = GICv3_IDLE_PRIORITY;
> +	int i, lr = -1;
> +
> +	for (i = 0; i < used_lrs; i++) {
> +		u64 val = __gic_v3_get_lr(i);
> +		u8 lr_prio = (val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
> +
> +		/* Not pending in the state? */
> +		if ((val & ICH_LR_STATE) != ICH_LR_PENDING_BIT)
> +			continue;
> +
> +		/* Group-0 interrupt, but Group-0 disabled? */
> +		if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG0_MASK))
> +			continue;
> +
> +		/* Group-1 interrupt, but Group-1 disabled? */
> +		if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG1_MASK))
> +			continue;
> +
> +		/* Not the highest priority? */
> +		if (lr_prio >= priority)
> +			continue;
> +
> +		/* This is a candidate */
> +		priority = lr_prio;
> +		*lr_val = val;
> +		lr = i;
> +	}
> +
> +	if (lr == -1)
> +		*lr_val = ICC_IAR1_EL1_SPURIOUS;
> +
> +	return lr;
> +}
> +
> +static int __hyp_text __vgic_v3_get_highest_active_priority(void)
> +{
> +	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> +	u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
> +	u32 hap = 0;
> +	int i;
> +
> +	for (i = 0; i < nr_apr_regs; i++) {
> +		u32 val;
> +
> +		val  = __vgic_v3_read_ap0rn(i);
> +		val |= __vgic_v3_read_ap1rn(i);
> +		if (!val) {
> +			hap += 32;
> +			continue;
> +		}
> +
> +		return (hap + __ffs(val)) << (8 - nr_pre_bits);

I don't understand this shift, and I think I asked about it before, so
maybe if it's a reused concept we can use a static inline or@least
provide a comment?

> +	}
> +
> +	return GICv3_IDLE_PRIORITY;
> +}
> +
>  static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
>  {
>  	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
> @@ -395,6 +469,79 @@ static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
>  	return bpr;
>  }
>  
> +/*
> + * Convert a priority to a preemption level, taking the relevant BPR
> + * into account by zeroing the sub-priority bits.
> + */
> +static u8 __hyp_text __vgic_v3_pri_to_pre(u8 pri, u32 vmcr, int grp)
> +{
> +	unsigned int bpr;
> +
> +	if (!grp)
> +		bpr = __vgic_v3_get_bpr0(vmcr) + 1;
> +	else
> +		bpr = __vgic_v3_get_bpr1(vmcr);
> +
> +	return pri & (GENMASK(7, 0) << bpr);
> +}
> +
> +/*
> + * The priority value is independent of any of the BPR values, so we
> + * normalize it using nr_pre_bits. This guarantees that no matter what
> + * the guest does with its BPR, we can always set/get the same value
> + * of a priority.
> + */
> +static void __hyp_text __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp)
> +{
> +	u8 nr_pre_bits, pre, ap;
> +	u32 val;
> +	int apr;
> +
> +	nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> +	pre = __vgic_v3_pri_to_pre(pri, vmcr, grp);
> +	ap = pre >> (8 - nr_pre_bits);

Again here, I don't get this shift.

> +	apr = ap / 32;
> +
> +	val = __vgic_v3_read_ap1rn(apr);
> +	__vgic_v3_write_ap1rn(val | BIT(ap % 32), apr);

How are we sure this is a group 1 interrupt here?

> +}
> +
> +static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> +{
> +	u64 lr_val;
> +	u8 lr_prio, pmr;
> +	int lr, grp;
> +
> +	grp = __vgic_v3_get_group(vcpu);
> +
> +	lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
> +	if (lr < 0)
> +		goto spurious;
> +
> +	if (grp != !!(lr_val & ICH_LR_GROUP))
> +		goto spurious;
> +
> +	pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
> +	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
> +	if (pmr <= lr_prio)
> +		goto spurious;
> +
> +	if (__vgic_v3_get_highest_active_priority() <= lr_prio)
> +		goto spurious;
> +
> +	lr_val &= ~ICH_LR_STATE;
> +	/* No active state for LPIs */
> +	if ((lr_val & ICH_LR_VIRTUAL_ID_MASK) <= VGIC_MAX_SPI)
> +		lr_val |= ICH_LR_ACTIVE_BIT;
> +	__gic_v3_set_lr(lr_val, lr);
> +	__vgic_v3_set_active_priority(lr_prio, vmcr, grp);
> +	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
> +	return;
> +
> +spurious:
> +	vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS);
> +}
> +
>  static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  {
>  	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
> @@ -459,6 +606,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
>  
>  	switch (sysreg) {
> +	case SYS_ICC_IAR1_EL1:
> +		fn = __vgic_v3_read_iar;
> +		break;

So we don't provide a write-ignore function here because we rely on the
hardware to always trap that at EL1 instead?

I remember we discussed this before, but I don't remember if the
conclusion was that this is 100% safe.


>  	case SYS_ICC_GRPEN1_EL1:
>  		if (is_read)
>  			fn = __vgic_v3_read_igrpen1;
> -- 
> 2.11.0
> 

Thanks,
-Christoffer

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

* Re: [PATCH v2 05/25] KVM: arm64: vgic-v3: Add ICV_BPR1_EL1 handler
  2017-06-04 20:25     ` Christoffer Dall
@ 2017-06-05  9:58       ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-05  9:58 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On 04/06/17 21:25, Christoffer Dall wrote:
> On Thu, Jun 01, 2017 at 11:20:57AM +0100, Marc Zyngier wrote:
>> Add a handler for reading/writing the guest's view of the ICC_BPR1_EL1
>> register, which is located in the ICH_VMCR_EL2.BPR1 field.
>>
>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  virt/kvm/arm/hyp/vgic-v3-sr.c | 51 +++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 51 insertions(+)
>>
>> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> index 943bf11252d9..6254eaf72a77 100644
>> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
>> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> @@ -375,6 +375,51 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
>>  
>>  #ifdef CONFIG_ARM64
>>  
>> +static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
>> +{
>> +	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
>> +}
>> +
>> +static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
>> +{
>> +	unsigned int bpr;
>> +
>> +	if (vmcr & ICH_VMCR_CBPR_MASK) {
>> +		bpr = __vgic_v3_get_bpr0(vmcr);
>> +		if (bpr < 7)
>> +			bpr++;
>> +	} else {
>> +		bpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
>> +	}
>> +
>> +	return bpr;
>> +}
>> +
>> +static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>> +{
>> +	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
>> +}
>> +
>> +static void __hyp_text __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>> +{
>> +	u64 val = vcpu_get_reg(vcpu, rt);
>> +	u8 bpr_min = 8 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> 
> I can't seem to find where this behavior is documented, is it that 8 is
> the theoretical max, and it's the upper preemption levels that apply, so
> it must be 8 - number supported?

I took inspiration from the VPriorityGroup() helper in the GICv3
pseudocode. You can also deduct this from the table described in the
ICC_BPR0_EL1 documentation, though that's admittedly not very clear.

>> +
>> +	if (vmcr & ICH_VMCR_CBPR_MASK)
>> +		return;
>> +
>> +	/* Enforce BPR limiting */
>> +	if (val < bpr_min)
>> +		val = bpr_min;
> 
> Are we not implying that the reset value here also means bpr_min?  I
> also can't seem to find this behavior in the spec and it appears we rely
> on the underlying hardware to set a reset value (by setting vmcr=0 on
> first run).  Could this result in a guest observing one reset value,
> writing 0 to this register, and observing another one?

>From the ICC_BPR0_EL1 documentation:

"An attempt to program the binary point field to a value less than the
minimum value sets the field to the minimum value."

That's the only way you can find out about the minimum value (and the
kernel also uses this functionality to be in a known state, even if it
doesn't use preemption yet).

> 
>> +
>> +	val <<= ICH_VMCR_BPR1_SHIFT;
>> +	val &= ICH_VMCR_BPR1_MASK;
>> +	vmcr &= ~ICH_VMCR_BPR1_MASK;
>> +	vmcr |= val;
>> +
>> +	__vgic_v3_write_vmcr(vmcr);
>> +}
>> +
>>  int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>>  {
>>  	int rt;
>> @@ -397,6 +442,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>>  	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
>>  
>>  	switch (sysreg) {
>> +	case SYS_ICC_BPR1_EL1:
>> +		if (is_read)
>> +			fn = __vgic_v3_read_bpr1;
>> +		else
>> +			fn = __vgic_v3_write_bpr1;
>> +		break;
> 
> Did you consider a lookup table with the sysreg encoding, the read
> function, and the right function as each entry?  It may compress the
> code a bit, but I'm not sure if it's nicer or worth it.

I did think of it, but I wasn't sure how much nicer that would be. Happy
to try it and see if that's an improvement though.

Thanks,

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

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

* [PATCH v2 05/25] KVM: arm64: vgic-v3: Add ICV_BPR1_EL1 handler
@ 2017-06-05  9:58       ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-05  9:58 UTC (permalink / raw)
  To: linux-arm-kernel

On 04/06/17 21:25, Christoffer Dall wrote:
> On Thu, Jun 01, 2017 at 11:20:57AM +0100, Marc Zyngier wrote:
>> Add a handler for reading/writing the guest's view of the ICC_BPR1_EL1
>> register, which is located in the ICH_VMCR_EL2.BPR1 field.
>>
>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  virt/kvm/arm/hyp/vgic-v3-sr.c | 51 +++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 51 insertions(+)
>>
>> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> index 943bf11252d9..6254eaf72a77 100644
>> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
>> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> @@ -375,6 +375,51 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
>>  
>>  #ifdef CONFIG_ARM64
>>  
>> +static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
>> +{
>> +	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
>> +}
>> +
>> +static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
>> +{
>> +	unsigned int bpr;
>> +
>> +	if (vmcr & ICH_VMCR_CBPR_MASK) {
>> +		bpr = __vgic_v3_get_bpr0(vmcr);
>> +		if (bpr < 7)
>> +			bpr++;
>> +	} else {
>> +		bpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
>> +	}
>> +
>> +	return bpr;
>> +}
>> +
>> +static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>> +{
>> +	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
>> +}
>> +
>> +static void __hyp_text __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>> +{
>> +	u64 val = vcpu_get_reg(vcpu, rt);
>> +	u8 bpr_min = 8 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> 
> I can't seem to find where this behavior is documented, is it that 8 is
> the theoretical max, and it's the upper preemption levels that apply, so
> it must be 8 - number supported?

I took inspiration from the VPriorityGroup() helper in the GICv3
pseudocode. You can also deduct this from the table described in the
ICC_BPR0_EL1 documentation, though that's admittedly not very clear.

>> +
>> +	if (vmcr & ICH_VMCR_CBPR_MASK)
>> +		return;
>> +
>> +	/* Enforce BPR limiting */
>> +	if (val < bpr_min)
>> +		val = bpr_min;
> 
> Are we not implying that the reset value here also means bpr_min?  I
> also can't seem to find this behavior in the spec and it appears we rely
> on the underlying hardware to set a reset value (by setting vmcr=0 on
> first run).  Could this result in a guest observing one reset value,
> writing 0 to this register, and observing another one?

>From the ICC_BPR0_EL1 documentation:

"An attempt to program the binary point field to a value less than the
minimum value sets the field to the minimum value."

That's the only way you can find out about the minimum value (and the
kernel also uses this functionality to be in a known state, even if it
doesn't use preemption yet).

> 
>> +
>> +	val <<= ICH_VMCR_BPR1_SHIFT;
>> +	val &= ICH_VMCR_BPR1_MASK;
>> +	vmcr &= ~ICH_VMCR_BPR1_MASK;
>> +	vmcr |= val;
>> +
>> +	__vgic_v3_write_vmcr(vmcr);
>> +}
>> +
>>  int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>>  {
>>  	int rt;
>> @@ -397,6 +442,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>>  	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
>>  
>>  	switch (sysreg) {
>> +	case SYS_ICC_BPR1_EL1:
>> +		if (is_read)
>> +			fn = __vgic_v3_read_bpr1;
>> +		else
>> +			fn = __vgic_v3_write_bpr1;
>> +		break;
> 
> Did you consider a lookup table with the sysreg encoding, the read
> function, and the right function as each entry?  It may compress the
> code a bit, but I'm not sure if it's nicer or worth it.

I did think of it, but I wasn't sure how much nicer that would be. Happy
to try it and see if that's an improvement though.

Thanks,

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

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

* Re: [PATCH v2 05/25] KVM: arm64: vgic-v3: Add ICV_BPR1_EL1 handler
  2017-06-05  9:58       ` Marc Zyngier
@ 2017-06-05 10:16         ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-05 10:16 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On Mon, Jun 05, 2017 at 10:58:57AM +0100, Marc Zyngier wrote:
> On 04/06/17 21:25, Christoffer Dall wrote:
> > On Thu, Jun 01, 2017 at 11:20:57AM +0100, Marc Zyngier wrote:
> >> Add a handler for reading/writing the guest's view of the ICC_BPR1_EL1
> >> register, which is located in the ICH_VMCR_EL2.BPR1 field.
> >>
> >> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> ---
> >>  virt/kvm/arm/hyp/vgic-v3-sr.c | 51 +++++++++++++++++++++++++++++++++++++++++++
> >>  1 file changed, 51 insertions(+)
> >>
> >> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> index 943bf11252d9..6254eaf72a77 100644
> >> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> @@ -375,6 +375,51 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
> >>  
> >>  #ifdef CONFIG_ARM64
> >>  
> >> +static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
> >> +{
> >> +	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
> >> +}
> >> +
> >> +static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
> >> +{
> >> +	unsigned int bpr;
> >> +
> >> +	if (vmcr & ICH_VMCR_CBPR_MASK) {
> >> +		bpr = __vgic_v3_get_bpr0(vmcr);
> >> +		if (bpr < 7)
> >> +			bpr++;
> >> +	} else {
> >> +		bpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
> >> +	}
> >> +
> >> +	return bpr;
> >> +}
> >> +
> >> +static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >> +{
> >> +	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
> >> +}
> >> +
> >> +static void __hyp_text __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >> +{
> >> +	u64 val = vcpu_get_reg(vcpu, rt);
> >> +	u8 bpr_min = 8 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> > 
> > I can't seem to find where this behavior is documented, is it that 8 is
> > the theoretical max, and it's the upper preemption levels that apply, so
> > it must be 8 - number supported?
> 
> I took inspiration from the VPriorityGroup() helper in the GICv3
> pseudocode. You can also deduct this from the table described in the
> ICC_BPR0_EL1 documentation, though that's admittedly not very clear.
> 
> >> +
> >> +	if (vmcr & ICH_VMCR_CBPR_MASK)
> >> +		return;
> >> +
> >> +	/* Enforce BPR limiting */
> >> +	if (val < bpr_min)
> >> +		val = bpr_min;
> > 
> > Are we not implying that the reset value here also means bpr_min?  I
> > also can't seem to find this behavior in the spec and it appears we rely
> > on the underlying hardware to set a reset value (by setting vmcr=0 on
> > first run).  Could this result in a guest observing one reset value,
> > writing 0 to this register, and observing another one?
> 
> From the ICC_BPR0_EL1 documentation:
> 
> "An attempt to program the binary point field to a value less than the
> minimum value sets the field to the minimum value."
> 
> That's the only way you can find out about the minimum value (and the
> kernel also uses this functionality to be in a known state, even if it
> doesn't use preemption yet).
> 

Hmm, the ICV_BPR0_EL1 says:
  "An attempt to program the binary point field to a value less than the
  minimum value sets the field to the minimum value. On a reset, the
  binary point field is set to the minimum supported value."

But then the ICV_BPR1_EL1 says:
  "An attempt to program the binary point field to a value less than the
  reset value sets the field to the reset value."

  and

  "Writing 0 to this field will set this field to its reset value, which
  is IMPLEMENTATION DEFINED and non-zero."

So it seems like the spec is making some distinction between minimum or
reset value and between the two registers, but I'm not sure if the spec
is just having its fun with us, or if there's something important to be
aware of here.


> > 
> >> +
> >> +	val <<= ICH_VMCR_BPR1_SHIFT;
> >> +	val &= ICH_VMCR_BPR1_MASK;
> >> +	vmcr &= ~ICH_VMCR_BPR1_MASK;
> >> +	vmcr |= val;
> >> +
> >> +	__vgic_v3_write_vmcr(vmcr);
> >> +}
> >> +
> >>  int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
> >>  {
> >>  	int rt;
> >> @@ -397,6 +442,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
> >>  	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
> >>  
> >>  	switch (sysreg) {
> >> +	case SYS_ICC_BPR1_EL1:
> >> +		if (is_read)
> >> +			fn = __vgic_v3_read_bpr1;
> >> +		else
> >> +			fn = __vgic_v3_write_bpr1;
> >> +		break;
> > 
> > Did you consider a lookup table with the sysreg encoding, the read
> > function, and the right function as each entry?  It may compress the
> > code a bit, but I'm not sure if it's nicer or worth it.
> 
> I did think of it, but I wasn't sure how much nicer that would be. Happy
> to try it and see if that's an improvement though.
> 

Meh, probably not worth it.

Thanks,
-Christoffer

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

* [PATCH v2 05/25] KVM: arm64: vgic-v3: Add ICV_BPR1_EL1 handler
@ 2017-06-05 10:16         ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-05 10:16 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jun 05, 2017 at 10:58:57AM +0100, Marc Zyngier wrote:
> On 04/06/17 21:25, Christoffer Dall wrote:
> > On Thu, Jun 01, 2017 at 11:20:57AM +0100, Marc Zyngier wrote:
> >> Add a handler for reading/writing the guest's view of the ICC_BPR1_EL1
> >> register, which is located in the ICH_VMCR_EL2.BPR1 field.
> >>
> >> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> ---
> >>  virt/kvm/arm/hyp/vgic-v3-sr.c | 51 +++++++++++++++++++++++++++++++++++++++++++
> >>  1 file changed, 51 insertions(+)
> >>
> >> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> index 943bf11252d9..6254eaf72a77 100644
> >> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> @@ -375,6 +375,51 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
> >>  
> >>  #ifdef CONFIG_ARM64
> >>  
> >> +static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
> >> +{
> >> +	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
> >> +}
> >> +
> >> +static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
> >> +{
> >> +	unsigned int bpr;
> >> +
> >> +	if (vmcr & ICH_VMCR_CBPR_MASK) {
> >> +		bpr = __vgic_v3_get_bpr0(vmcr);
> >> +		if (bpr < 7)
> >> +			bpr++;
> >> +	} else {
> >> +		bpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
> >> +	}
> >> +
> >> +	return bpr;
> >> +}
> >> +
> >> +static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >> +{
> >> +	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
> >> +}
> >> +
> >> +static void __hyp_text __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >> +{
> >> +	u64 val = vcpu_get_reg(vcpu, rt);
> >> +	u8 bpr_min = 8 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> > 
> > I can't seem to find where this behavior is documented, is it that 8 is
> > the theoretical max, and it's the upper preemption levels that apply, so
> > it must be 8 - number supported?
> 
> I took inspiration from the VPriorityGroup() helper in the GICv3
> pseudocode. You can also deduct this from the table described in the
> ICC_BPR0_EL1 documentation, though that's admittedly not very clear.
> 
> >> +
> >> +	if (vmcr & ICH_VMCR_CBPR_MASK)
> >> +		return;
> >> +
> >> +	/* Enforce BPR limiting */
> >> +	if (val < bpr_min)
> >> +		val = bpr_min;
> > 
> > Are we not implying that the reset value here also means bpr_min?  I
> > also can't seem to find this behavior in the spec and it appears we rely
> > on the underlying hardware to set a reset value (by setting vmcr=0 on
> > first run).  Could this result in a guest observing one reset value,
> > writing 0 to this register, and observing another one?
> 
> From the ICC_BPR0_EL1 documentation:
> 
> "An attempt to program the binary point field to a value less than the
> minimum value sets the field to the minimum value."
> 
> That's the only way you can find out about the minimum value (and the
> kernel also uses this functionality to be in a known state, even if it
> doesn't use preemption yet).
> 

Hmm, the ICV_BPR0_EL1 says:
  "An attempt to program the binary point field to a value less than the
  minimum value sets the field to the minimum value. On a reset, the
  binary point field is set to the minimum supported value."

But then the ICV_BPR1_EL1 says:
  "An attempt to program the binary point field to a value less than the
  reset value sets the field to the reset value."

  and

  "Writing 0 to this field will set this field to its reset value, which
  is IMPLEMENTATION DEFINED and non-zero."

So it seems like the spec is making some distinction between minimum or
reset value and between the two registers, but I'm not sure if the spec
is just having its fun with us, or if there's something important to be
aware of here.


> > 
> >> +
> >> +	val <<= ICH_VMCR_BPR1_SHIFT;
> >> +	val &= ICH_VMCR_BPR1_MASK;
> >> +	vmcr &= ~ICH_VMCR_BPR1_MASK;
> >> +	vmcr |= val;
> >> +
> >> +	__vgic_v3_write_vmcr(vmcr);
> >> +}
> >> +
> >>  int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
> >>  {
> >>  	int rt;
> >> @@ -397,6 +442,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
> >>  	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
> >>  
> >>  	switch (sysreg) {
> >> +	case SYS_ICC_BPR1_EL1:
> >> +		if (is_read)
> >> +			fn = __vgic_v3_read_bpr1;
> >> +		else
> >> +			fn = __vgic_v3_write_bpr1;
> >> +		break;
> > 
> > Did you consider a lookup table with the sysreg encoding, the read
> > function, and the right function as each entry?  It may compress the
> > code a bit, but I'm not sure if it's nicer or worth it.
> 
> I did think of it, but I wasn't sure how much nicer that would be. Happy
> to try it and see if that's an improvement though.
> 

Meh, probably not worth it.

Thanks,
-Christoffer

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

* Re: [PATCH v2 05/25] KVM: arm64: vgic-v3: Add ICV_BPR1_EL1 handler
  2017-06-05 10:16         ` Christoffer Dall
@ 2017-06-05 10:27           ` Peter Maydell
  -1 siblings, 0 replies; 152+ messages in thread
From: Peter Maydell @ 2017-06-05 10:27 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Marc Zyngier, kvm-devel, David Daney, Catalin Marinas,
	Robert Richter, arm-mail-list, kvmarm

On 5 June 2017 at 11:16, Christoffer Dall <cdall@linaro.org> wrote:
> On Mon, Jun 05, 2017 at 10:58:57AM +0100, Marc Zyngier wrote:
>> From the ICC_BPR0_EL1 documentation:
>>
>> "An attempt to program the binary point field to a value less than the
>> minimum value sets the field to the minimum value."
>>
>> That's the only way you can find out about the minimum value (and the
>> kernel also uses this functionality to be in a known state, even if it
>> doesn't use preemption yet).
>>
>
> Hmm, the ICV_BPR0_EL1 says:
>   "An attempt to program the binary point field to a value less than the
>   minimum value sets the field to the minimum value. On a reset, the
>   binary point field is set to the minimum supported value."
>
> But then the ICV_BPR1_EL1 says:
>   "An attempt to program the binary point field to a value less than the
>   reset value sets the field to the reset value."
>
>   and
>
>   "Writing 0 to this field will set this field to its reset value, which
>   is IMPLEMENTATION DEFINED and non-zero."

It also later says that the ICV_BPR1_EL1 IMPDEF reset value is always
the ICV_BPR0_EL1 reset value plus one.

> So it seems like the spec is making some distinction between minimum or
> reset value and between the two registers, but I'm not sure if the spec
> is just having its fun with us, or if there's something important to be
> aware of here.

I think the plus-one is the only interesting difference and the
rest is just accidental difference of wording.

There is a difference between ICV_BPR* and ICC_BPR*, which is that
the latter reset to an UNKNOWN value, not necessarily the minimum.

thanks
-- PMM

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

* [PATCH v2 05/25] KVM: arm64: vgic-v3: Add ICV_BPR1_EL1 handler
@ 2017-06-05 10:27           ` Peter Maydell
  0 siblings, 0 replies; 152+ messages in thread
From: Peter Maydell @ 2017-06-05 10:27 UTC (permalink / raw)
  To: linux-arm-kernel

On 5 June 2017 at 11:16, Christoffer Dall <cdall@linaro.org> wrote:
> On Mon, Jun 05, 2017 at 10:58:57AM +0100, Marc Zyngier wrote:
>> From the ICC_BPR0_EL1 documentation:
>>
>> "An attempt to program the binary point field to a value less than the
>> minimum value sets the field to the minimum value."
>>
>> That's the only way you can find out about the minimum value (and the
>> kernel also uses this functionality to be in a known state, even if it
>> doesn't use preemption yet).
>>
>
> Hmm, the ICV_BPR0_EL1 says:
>   "An attempt to program the binary point field to a value less than the
>   minimum value sets the field to the minimum value. On a reset, the
>   binary point field is set to the minimum supported value."
>
> But then the ICV_BPR1_EL1 says:
>   "An attempt to program the binary point field to a value less than the
>   reset value sets the field to the reset value."
>
>   and
>
>   "Writing 0 to this field will set this field to its reset value, which
>   is IMPLEMENTATION DEFINED and non-zero."

It also later says that the ICV_BPR1_EL1 IMPDEF reset value is always
the ICV_BPR0_EL1 reset value plus one.

> So it seems like the spec is making some distinction between minimum or
> reset value and between the two registers, but I'm not sure if the spec
> is just having its fun with us, or if there's something important to be
> aware of here.

I think the plus-one is the only interesting difference and the
rest is just accidental difference of wording.

There is a difference between ICV_BPR* and ICC_BPR*, which is that
the latter reset to an UNKNOWN value, not necessarily the minimum.

thanks
-- PMM

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

* Re: [PATCH v2 08/25] KVM: arm64: vgic-v3: Add ICV_EOIR1_EL1 handler
  2017-06-01 10:21   ` Marc Zyngier
@ 2017-06-05 10:32     ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-05 10:32 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter,
	linux-arm-kernel, kvmarm

On Thu, Jun 01, 2017 at 11:21:00AM +0100, Marc Zyngier wrote:
> Add a handler for writing the guest's view of the ICC_EOIR1_EL1
> register. This involves dropping the priority of the interrupt,
> and deactivating it if required (EOImode == 0).
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  include/linux/irqchip/arm-gic-v3.h |   2 +
>  virt/kvm/arm/hyp/vgic-v3-sr.c      | 121 +++++++++++++++++++++++++++++++++++++
>  2 files changed, 123 insertions(+)
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index 401db585a534..e50ce5d416a3 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -417,6 +417,8 @@
>  
>  #define ICH_HCR_EN			(1 << 0)
>  #define ICH_HCR_UIE			(1 << 1)
> +#define ICH_HCR_EOIcount_SHIFT		27
> +#define ICH_HCR_EOIcount_MASK		(0x1f << ICH_HCR_EOIcount_SHIFT)
>  
>  #define ICH_VMCR_CBPR_SHIFT		4
>  #define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 16a2eadc7a5c..3f04122a5d4d 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -426,6 +426,26 @@ static int __hyp_text __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu,
>  	return lr;
>  }
>  
> +static int __hyp_text __vgic_v3_find_active_lr(struct kvm_vcpu *vcpu,
> +					       int intid, u64 *lr_val)
> +{
> +	unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
> +	int i;
> +
> +	for (i = 0; i < used_lrs; i++) {
> +		u64 val = __gic_v3_get_lr(i);
> +
> +		if ((val & ICH_LR_VIRTUAL_ID_MASK) == intid &&
> +		    (val & ICH_LR_ACTIVE_BIT)) {
> +			*lr_val = val;
> +			return i;
> +		}
> +	}
> +
> +	*lr_val = ICC_IAR1_EL1_SPURIOUS;
> +	return -1;
> +}
> +
>  static int __hyp_text __vgic_v3_get_highest_active_priority(void)
>  {
>  	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> @@ -506,6 +526,45 @@ static void __hyp_text __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp)
>  	__vgic_v3_write_ap1rn(val | BIT(ap % 32), apr);
>  }
>  
> +static int __hyp_text __vgic_v3_clear_highest_active_priority(void)
> +{
> +	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> +	u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
> +	u32 hap = 0;
> +	int i;
> +
> +	for (i = 0; i < nr_apr_regs; i++) {
> +		u32 ap0, ap1;
> +		int c0, c1;
> +
> +		ap0 = __vgic_v3_read_ap0rn(i);
> +		ap1 = __vgic_v3_read_ap1rn(i);

so reading a group 1 interrupt from the IAR and writing that value back
to the EOIR1_EL1 register can somehow clear the priority of a group 0
interrupt?

Or did you just want a generic function that does what it's supposed to
regardless of which register was written to etc.?

> +		if (!ap0 && !ap1) {
> +			hap += 32;
> +			continue;
> +		}
> +
> +		c0 = ap0 ? __ffs(ap0) : 32;
> +		c1 = ap1 ? __ffs(ap1) : 32;
> +
> +		/* Always clear the LSB, which is the highest priority */
> +		if (c0 < c1) {
> +			ap0 &= ~BIT(c0);
> +			__vgic_v3_write_ap0rn(ap0, i);
> +			hap += c0;
> +		} else {
> +			ap1 &= ~BIT(c1);
> +			__vgic_v3_write_ap1rn(ap1, i);
> +			hap += c1;

Can we ever have a situation where c0 == c1?  And in that case, should
you prioritize clearing the group 1 apr ?

> +		}
> +
> +		/* Rescale to 8 bits of priority */
> +		return hap << (8 - nr_pre_bits);
> +	}
> +
> +	return GICv3_IDLE_PRIORITY;
> +}
> +
>  static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  {
>  	u64 lr_val;
> @@ -542,6 +601,65 @@ static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int r
>  	vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS);
>  }
>  
> +static void __hyp_text __vgic_v3_clear_active_lr(int lr, u64 lr_val)
> +{
> +	lr_val &= ~ICH_LR_ACTIVE_BIT;
> +	if (lr_val & ICH_LR_HW) {
> +		u32 pid;
> +
> +		pid = (lr_val & ICH_LR_PHYS_ID_MASK) >> ICH_LR_PHYS_ID_SHIFT;
> +		gic_write_dir(pid);

Yikes, scary.  I can't think of this breaking anything.  But, scary.


> +	}
> +
> +	__gic_v3_set_lr(lr_val, lr);
> +}
> +
> +static void __hyp_text __vgic_v3_bump_eoicount(void)
> +{
> +	u32 hcr;
> +
> +	hcr = read_gicreg(ICH_HCR_EL2);
> +	hcr += 1 << ICH_HCR_EOIcount_SHIFT;
> +	write_gicreg(hcr, ICH_HCR_EL2);
> +}
> +
> +static void __hyp_text __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> +{
> +	u32 vid = vcpu_get_reg(vcpu, rt);
> +	u64 lr_val;
> +	u8 lr_prio, act_prio;
> +	int lr, grp;
> +
> +	grp = __vgic_v3_get_group(vcpu);
> +
> +	/* Drop priority in any case */
> +	act_prio = __vgic_v3_clear_highest_active_priority();
> +
> +	/* If EOIing an LPI, no deactivate to be performed */
> +	if (vid >= VGIC_MIN_LPI)
> +		return;
> +
> +	/* EOImode == 1, nothing to be done here */
> +	if (vmcr & ICH_VMCR_EOIM_MASK)
> +		return;
> +
> +	lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val);
> +	if (lr == -1) {
> +		__vgic_v3_bump_eoicount();
> +		return;
> +	}
> +
> +	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
> +
> +	/* If priorities or group do not match, the guest has fscked-up. */
> +	if (grp != !!(lr_val & ICH_LR_GROUP) ||
> +	    __vgic_v3_pri_to_pre(lr_prio, vmcr, grp) != act_prio)
> +		return;

Since we've cleared the highest priority above, is there any way for the
guest to recover from this, or do this particular (v)GIC implementation
have the implementation defined behavior of a write with something else
than the last valid read from the IAR of the same group to the EOIR
means that the system is toast?

> +
> +	/* Let's now perform the deactivation */
> +	__vgic_v3_clear_active_lr(lr, lr_val);
> +}
> +
>  static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  {
>  	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
> @@ -609,6 +727,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  	case SYS_ICC_IAR1_EL1:
>  		fn = __vgic_v3_read_iar;
>  		break;
> +	case SYS_ICC_EOIR1_EL1:
> +		fn = __vgic_v3_write_eoir;
> +		break;
>  	case SYS_ICC_GRPEN1_EL1:
>  		if (is_read)
>  			fn = __vgic_v3_read_igrpen1;
> -- 
> 2.11.0
> 

Thanks,
-Christoffer

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

* [PATCH v2 08/25] KVM: arm64: vgic-v3: Add ICV_EOIR1_EL1 handler
@ 2017-06-05 10:32     ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-05 10:32 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 01, 2017 at 11:21:00AM +0100, Marc Zyngier wrote:
> Add a handler for writing the guest's view of the ICC_EOIR1_EL1
> register. This involves dropping the priority of the interrupt,
> and deactivating it if required (EOImode == 0).
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  include/linux/irqchip/arm-gic-v3.h |   2 +
>  virt/kvm/arm/hyp/vgic-v3-sr.c      | 121 +++++++++++++++++++++++++++++++++++++
>  2 files changed, 123 insertions(+)
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index 401db585a534..e50ce5d416a3 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -417,6 +417,8 @@
>  
>  #define ICH_HCR_EN			(1 << 0)
>  #define ICH_HCR_UIE			(1 << 1)
> +#define ICH_HCR_EOIcount_SHIFT		27
> +#define ICH_HCR_EOIcount_MASK		(0x1f << ICH_HCR_EOIcount_SHIFT)
>  
>  #define ICH_VMCR_CBPR_SHIFT		4
>  #define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 16a2eadc7a5c..3f04122a5d4d 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -426,6 +426,26 @@ static int __hyp_text __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu,
>  	return lr;
>  }
>  
> +static int __hyp_text __vgic_v3_find_active_lr(struct kvm_vcpu *vcpu,
> +					       int intid, u64 *lr_val)
> +{
> +	unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
> +	int i;
> +
> +	for (i = 0; i < used_lrs; i++) {
> +		u64 val = __gic_v3_get_lr(i);
> +
> +		if ((val & ICH_LR_VIRTUAL_ID_MASK) == intid &&
> +		    (val & ICH_LR_ACTIVE_BIT)) {
> +			*lr_val = val;
> +			return i;
> +		}
> +	}
> +
> +	*lr_val = ICC_IAR1_EL1_SPURIOUS;
> +	return -1;
> +}
> +
>  static int __hyp_text __vgic_v3_get_highest_active_priority(void)
>  {
>  	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> @@ -506,6 +526,45 @@ static void __hyp_text __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp)
>  	__vgic_v3_write_ap1rn(val | BIT(ap % 32), apr);
>  }
>  
> +static int __hyp_text __vgic_v3_clear_highest_active_priority(void)
> +{
> +	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> +	u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
> +	u32 hap = 0;
> +	int i;
> +
> +	for (i = 0; i < nr_apr_regs; i++) {
> +		u32 ap0, ap1;
> +		int c0, c1;
> +
> +		ap0 = __vgic_v3_read_ap0rn(i);
> +		ap1 = __vgic_v3_read_ap1rn(i);

so reading a group 1 interrupt from the IAR and writing that value back
to the EOIR1_EL1 register can somehow clear the priority of a group 0
interrupt?

Or did you just want a generic function that does what it's supposed to
regardless of which register was written to etc.?

> +		if (!ap0 && !ap1) {
> +			hap += 32;
> +			continue;
> +		}
> +
> +		c0 = ap0 ? __ffs(ap0) : 32;
> +		c1 = ap1 ? __ffs(ap1) : 32;
> +
> +		/* Always clear the LSB, which is the highest priority */
> +		if (c0 < c1) {
> +			ap0 &= ~BIT(c0);
> +			__vgic_v3_write_ap0rn(ap0, i);
> +			hap += c0;
> +		} else {
> +			ap1 &= ~BIT(c1);
> +			__vgic_v3_write_ap1rn(ap1, i);
> +			hap += c1;

Can we ever have a situation where c0 == c1?  And in that case, should
you prioritize clearing the group 1 apr ?

> +		}
> +
> +		/* Rescale to 8 bits of priority */
> +		return hap << (8 - nr_pre_bits);
> +	}
> +
> +	return GICv3_IDLE_PRIORITY;
> +}
> +
>  static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  {
>  	u64 lr_val;
> @@ -542,6 +601,65 @@ static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int r
>  	vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS);
>  }
>  
> +static void __hyp_text __vgic_v3_clear_active_lr(int lr, u64 lr_val)
> +{
> +	lr_val &= ~ICH_LR_ACTIVE_BIT;
> +	if (lr_val & ICH_LR_HW) {
> +		u32 pid;
> +
> +		pid = (lr_val & ICH_LR_PHYS_ID_MASK) >> ICH_LR_PHYS_ID_SHIFT;
> +		gic_write_dir(pid);

Yikes, scary.  I can't think of this breaking anything.  But, scary.


> +	}
> +
> +	__gic_v3_set_lr(lr_val, lr);
> +}
> +
> +static void __hyp_text __vgic_v3_bump_eoicount(void)
> +{
> +	u32 hcr;
> +
> +	hcr = read_gicreg(ICH_HCR_EL2);
> +	hcr += 1 << ICH_HCR_EOIcount_SHIFT;
> +	write_gicreg(hcr, ICH_HCR_EL2);
> +}
> +
> +static void __hyp_text __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> +{
> +	u32 vid = vcpu_get_reg(vcpu, rt);
> +	u64 lr_val;
> +	u8 lr_prio, act_prio;
> +	int lr, grp;
> +
> +	grp = __vgic_v3_get_group(vcpu);
> +
> +	/* Drop priority in any case */
> +	act_prio = __vgic_v3_clear_highest_active_priority();
> +
> +	/* If EOIing an LPI, no deactivate to be performed */
> +	if (vid >= VGIC_MIN_LPI)
> +		return;
> +
> +	/* EOImode == 1, nothing to be done here */
> +	if (vmcr & ICH_VMCR_EOIM_MASK)
> +		return;
> +
> +	lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val);
> +	if (lr == -1) {
> +		__vgic_v3_bump_eoicount();
> +		return;
> +	}
> +
> +	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
> +
> +	/* If priorities or group do not match, the guest has fscked-up. */
> +	if (grp != !!(lr_val & ICH_LR_GROUP) ||
> +	    __vgic_v3_pri_to_pre(lr_prio, vmcr, grp) != act_prio)
> +		return;

Since we've cleared the highest priority above, is there any way for the
guest to recover from this, or do this particular (v)GIC implementation
have the implementation defined behavior of a write with something else
than the last valid read from the IAR of the same group to the EOIR
means that the system is toast?

> +
> +	/* Let's now perform the deactivation */
> +	__vgic_v3_clear_active_lr(lr, lr_val);
> +}
> +
>  static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  {
>  	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
> @@ -609,6 +727,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  	case SYS_ICC_IAR1_EL1:
>  		fn = __vgic_v3_read_iar;
>  		break;
> +	case SYS_ICC_EOIR1_EL1:
> +		fn = __vgic_v3_write_eoir;
> +		break;
>  	case SYS_ICC_GRPEN1_EL1:
>  		if (is_read)
>  			fn = __vgic_v3_read_igrpen1;
> -- 
> 2.11.0
> 

Thanks,
-Christoffer

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

* Re: [PATCH v2 07/25] KVM: arm64: vgic-v3: Add ICV_IAR1_EL1 handler
  2017-06-05  9:21     ` Christoffer Dall
@ 2017-06-05 10:33       ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-05 10:33 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On 05/06/17 10:21, Christoffer Dall wrote:
> On Thu, Jun 01, 2017 at 11:20:59AM +0100, Marc Zyngier wrote:
>> Add a handler for reading the guest's view of the ICC_IAR1_EL1
>> register. This involves finding the highest priority Group-1
>> interrupt, checking against both PMR and the active group
>> priority, activating the interrupt and setting the group
>> priority as active.
>>
>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  include/linux/irqchip/arm-gic-v3.h |   1 +
>>  virt/kvm/arm/hyp/vgic-v3-sr.c      | 150 +++++++++++++++++++++++++++++++++++++
>>  2 files changed, 151 insertions(+)
>>
>> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
>> index fffb91202bc9..401db585a534 100644
>> --- a/include/linux/irqchip/arm-gic-v3.h
>> +++ b/include/linux/irqchip/arm-gic-v3.h
>> @@ -405,6 +405,7 @@
>>  #define ICH_LR_PHYS_ID_SHIFT		32
>>  #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
>>  #define ICH_LR_PRIORITY_SHIFT		48
>> +#define ICH_LR_PRIORITY_MASK		(0xffULL << ICH_LR_PRIORITY_SHIFT)
>>  
>>  /* These are for GICv2 emulation only */
>>  #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
>> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> index 168539dfd0b9..16a2eadc7a5c 100644
>> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
>> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> @@ -24,6 +24,7 @@
>>  
>>  #define vtr_to_max_lr_idx(v)		((v) & 0xf)
>>  #define vtr_to_nr_pre_bits(v)		(((u32)(v) >> 26) + 1)
>> +#define vtr_to_nr_apr_regs(v)		(1 << (vtr_to_nr_pre_bits(v) - 5))
>>  
>>  static u64 __hyp_text __gic_v3_get_lr(unsigned int lr)
>>  {
>> @@ -375,6 +376,79 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
>>  
>>  #ifdef CONFIG_ARM64
>>  
>> +static int __hyp_text __vgic_v3_get_group(struct kvm_vcpu *vcpu)
>> +{
>> +	u32 esr = kvm_vcpu_get_hsr(vcpu);
>> +	u8 crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT;
>> +
>> +	return crm != 8;
>> +}
>> +
>> +#define GICv3_IDLE_PRIORITY	0xff
>> +
>> +static int __hyp_text __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu,
>> +						    u32 vmcr,
>> +						    u64 *lr_val)
>> +{
>> +	unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
>> +	u8 priority = GICv3_IDLE_PRIORITY;
>> +	int i, lr = -1;
>> +
>> +	for (i = 0; i < used_lrs; i++) {
>> +		u64 val = __gic_v3_get_lr(i);
>> +		u8 lr_prio = (val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
>> +
>> +		/* Not pending in the state? */
>> +		if ((val & ICH_LR_STATE) != ICH_LR_PENDING_BIT)
>> +			continue;
>> +
>> +		/* Group-0 interrupt, but Group-0 disabled? */
>> +		if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG0_MASK))
>> +			continue;
>> +
>> +		/* Group-1 interrupt, but Group-1 disabled? */
>> +		if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG1_MASK))
>> +			continue;
>> +
>> +		/* Not the highest priority? */
>> +		if (lr_prio >= priority)
>> +			continue;
>> +
>> +		/* This is a candidate */
>> +		priority = lr_prio;
>> +		*lr_val = val;
>> +		lr = i;
>> +	}
>> +
>> +	if (lr == -1)
>> +		*lr_val = ICC_IAR1_EL1_SPURIOUS;
>> +
>> +	return lr;
>> +}
>> +
>> +static int __hyp_text __vgic_v3_get_highest_active_priority(void)
>> +{
>> +	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
>> +	u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
>> +	u32 hap = 0;
>> +	int i;
>> +
>> +	for (i = 0; i < nr_apr_regs; i++) {
>> +		u32 val;
>> +
>> +		val  = __vgic_v3_read_ap0rn(i);
>> +		val |= __vgic_v3_read_ap1rn(i);
>> +		if (!val) {
>> +			hap += 32;
>> +			continue;
>> +		}
>> +
>> +		return (hap + __ffs(val)) << (8 - nr_pre_bits);
> 
> I don't understand this shift, and I think I asked about it before, so
> maybe if it's a reused concept we can use a static inline or at least
> provide a comment?

I tried to explain it in my reply to your comment on patch #5. Can
definitely make that a helper. I think part of the confusion is that
this constant is used in a number of ways to express the conversion
between a preemption level and a priority.

>> +	}
>> +
>> +	return GICv3_IDLE_PRIORITY;
>> +}
>> +
>>  static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
>>  {
>>  	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
>> @@ -395,6 +469,79 @@ static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
>>  	return bpr;
>>  }
>>  
>> +/*
>> + * Convert a priority to a preemption level, taking the relevant BPR
>> + * into account by zeroing the sub-priority bits.
>> + */
>> +static u8 __hyp_text __vgic_v3_pri_to_pre(u8 pri, u32 vmcr, int grp)
>> +{
>> +	unsigned int bpr;
>> +
>> +	if (!grp)
>> +		bpr = __vgic_v3_get_bpr0(vmcr) + 1;
>> +	else
>> +		bpr = __vgic_v3_get_bpr1(vmcr);
>> +
>> +	return pri & (GENMASK(7, 0) << bpr);
>> +}
>> +
>> +/*
>> + * The priority value is independent of any of the BPR values, so we
>> + * normalize it using nr_pre_bits. This guarantees that no matter what
>> + * the guest does with its BPR, we can always set/get the same value
>> + * of a priority.
>> + */
>> +static void __hyp_text __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp)
>> +{
>> +	u8 nr_pre_bits, pre, ap;
>> +	u32 val;
>> +	int apr;
>> +
>> +	nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
>> +	pre = __vgic_v3_pri_to_pre(pri, vmcr, grp);
>> +	ap = pre >> (8 - nr_pre_bits);
> 
> Again here, I don't get this shift.
> 
>> +	apr = ap / 32;
>> +
>> +	val = __vgic_v3_read_ap1rn(apr);
>> +	__vgic_v3_write_ap1rn(val | BIT(ap % 32), apr);
> 
> How are we sure this is a group 1 interrupt here?

That's a bug, as we should definitely check grp here. Thanks for
noticing it!

>> +}
>> +
>> +static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>> +{
>> +	u64 lr_val;
>> +	u8 lr_prio, pmr;
>> +	int lr, grp;
>> +
>> +	grp = __vgic_v3_get_group(vcpu);
>> +
>> +	lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
>> +	if (lr < 0)
>> +		goto spurious;
>> +
>> +	if (grp != !!(lr_val & ICH_LR_GROUP))
>> +		goto spurious;
>> +
>> +	pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
>> +	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
>> +	if (pmr <= lr_prio)
>> +		goto spurious;
>> +
>> +	if (__vgic_v3_get_highest_active_priority() <= lr_prio)
>> +		goto spurious;
>> +
>> +	lr_val &= ~ICH_LR_STATE;
>> +	/* No active state for LPIs */
>> +	if ((lr_val & ICH_LR_VIRTUAL_ID_MASK) <= VGIC_MAX_SPI)
>> +		lr_val |= ICH_LR_ACTIVE_BIT;
>> +	__gic_v3_set_lr(lr_val, lr);
>> +	__vgic_v3_set_active_priority(lr_prio, vmcr, grp);
>> +	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
>> +	return;
>> +
>> +spurious:
>> +	vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS);
>> +}
>> +
>>  static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>>  {
>>  	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
>> @@ -459,6 +606,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>>  	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
>>  
>>  	switch (sysreg) {
>> +	case SYS_ICC_IAR1_EL1:
>> +		fn = __vgic_v3_read_iar;
>> +		break;
> 
> So we don't provide a write-ignore function here because we rely on the
> hardware to always trap that at EL1 instead?
> 
> I remember we discussed this before, but I don't remember if the
> conclusion was that this is 100% safe.

A properly designed CPU would UNDEF at EL1. I'm happy to try and detect
broken failing implementations here, but I'm not sure of what to do, as
we're not in the best context to handle this. We could continue exiting
to EL1 and handle things there...

Thanks,

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

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

* [PATCH v2 07/25] KVM: arm64: vgic-v3: Add ICV_IAR1_EL1 handler
@ 2017-06-05 10:33       ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-05 10:33 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/06/17 10:21, Christoffer Dall wrote:
> On Thu, Jun 01, 2017 at 11:20:59AM +0100, Marc Zyngier wrote:
>> Add a handler for reading the guest's view of the ICC_IAR1_EL1
>> register. This involves finding the highest priority Group-1
>> interrupt, checking against both PMR and the active group
>> priority, activating the interrupt and setting the group
>> priority as active.
>>
>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  include/linux/irqchip/arm-gic-v3.h |   1 +
>>  virt/kvm/arm/hyp/vgic-v3-sr.c      | 150 +++++++++++++++++++++++++++++++++++++
>>  2 files changed, 151 insertions(+)
>>
>> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
>> index fffb91202bc9..401db585a534 100644
>> --- a/include/linux/irqchip/arm-gic-v3.h
>> +++ b/include/linux/irqchip/arm-gic-v3.h
>> @@ -405,6 +405,7 @@
>>  #define ICH_LR_PHYS_ID_SHIFT		32
>>  #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
>>  #define ICH_LR_PRIORITY_SHIFT		48
>> +#define ICH_LR_PRIORITY_MASK		(0xffULL << ICH_LR_PRIORITY_SHIFT)
>>  
>>  /* These are for GICv2 emulation only */
>>  #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
>> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> index 168539dfd0b9..16a2eadc7a5c 100644
>> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
>> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> @@ -24,6 +24,7 @@
>>  
>>  #define vtr_to_max_lr_idx(v)		((v) & 0xf)
>>  #define vtr_to_nr_pre_bits(v)		(((u32)(v) >> 26) + 1)
>> +#define vtr_to_nr_apr_regs(v)		(1 << (vtr_to_nr_pre_bits(v) - 5))
>>  
>>  static u64 __hyp_text __gic_v3_get_lr(unsigned int lr)
>>  {
>> @@ -375,6 +376,79 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
>>  
>>  #ifdef CONFIG_ARM64
>>  
>> +static int __hyp_text __vgic_v3_get_group(struct kvm_vcpu *vcpu)
>> +{
>> +	u32 esr = kvm_vcpu_get_hsr(vcpu);
>> +	u8 crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT;
>> +
>> +	return crm != 8;
>> +}
>> +
>> +#define GICv3_IDLE_PRIORITY	0xff
>> +
>> +static int __hyp_text __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu,
>> +						    u32 vmcr,
>> +						    u64 *lr_val)
>> +{
>> +	unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
>> +	u8 priority = GICv3_IDLE_PRIORITY;
>> +	int i, lr = -1;
>> +
>> +	for (i = 0; i < used_lrs; i++) {
>> +		u64 val = __gic_v3_get_lr(i);
>> +		u8 lr_prio = (val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
>> +
>> +		/* Not pending in the state? */
>> +		if ((val & ICH_LR_STATE) != ICH_LR_PENDING_BIT)
>> +			continue;
>> +
>> +		/* Group-0 interrupt, but Group-0 disabled? */
>> +		if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG0_MASK))
>> +			continue;
>> +
>> +		/* Group-1 interrupt, but Group-1 disabled? */
>> +		if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG1_MASK))
>> +			continue;
>> +
>> +		/* Not the highest priority? */
>> +		if (lr_prio >= priority)
>> +			continue;
>> +
>> +		/* This is a candidate */
>> +		priority = lr_prio;
>> +		*lr_val = val;
>> +		lr = i;
>> +	}
>> +
>> +	if (lr == -1)
>> +		*lr_val = ICC_IAR1_EL1_SPURIOUS;
>> +
>> +	return lr;
>> +}
>> +
>> +static int __hyp_text __vgic_v3_get_highest_active_priority(void)
>> +{
>> +	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
>> +	u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
>> +	u32 hap = 0;
>> +	int i;
>> +
>> +	for (i = 0; i < nr_apr_regs; i++) {
>> +		u32 val;
>> +
>> +		val  = __vgic_v3_read_ap0rn(i);
>> +		val |= __vgic_v3_read_ap1rn(i);
>> +		if (!val) {
>> +			hap += 32;
>> +			continue;
>> +		}
>> +
>> +		return (hap + __ffs(val)) << (8 - nr_pre_bits);
> 
> I don't understand this shift, and I think I asked about it before, so
> maybe if it's a reused concept we can use a static inline or at least
> provide a comment?

I tried to explain it in my reply to your comment on patch #5. Can
definitely make that a helper. I think part of the confusion is that
this constant is used in a number of ways to express the conversion
between a preemption level and a priority.

>> +	}
>> +
>> +	return GICv3_IDLE_PRIORITY;
>> +}
>> +
>>  static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
>>  {
>>  	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
>> @@ -395,6 +469,79 @@ static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
>>  	return bpr;
>>  }
>>  
>> +/*
>> + * Convert a priority to a preemption level, taking the relevant BPR
>> + * into account by zeroing the sub-priority bits.
>> + */
>> +static u8 __hyp_text __vgic_v3_pri_to_pre(u8 pri, u32 vmcr, int grp)
>> +{
>> +	unsigned int bpr;
>> +
>> +	if (!grp)
>> +		bpr = __vgic_v3_get_bpr0(vmcr) + 1;
>> +	else
>> +		bpr = __vgic_v3_get_bpr1(vmcr);
>> +
>> +	return pri & (GENMASK(7, 0) << bpr);
>> +}
>> +
>> +/*
>> + * The priority value is independent of any of the BPR values, so we
>> + * normalize it using nr_pre_bits. This guarantees that no matter what
>> + * the guest does with its BPR, we can always set/get the same value
>> + * of a priority.
>> + */
>> +static void __hyp_text __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp)
>> +{
>> +	u8 nr_pre_bits, pre, ap;
>> +	u32 val;
>> +	int apr;
>> +
>> +	nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
>> +	pre = __vgic_v3_pri_to_pre(pri, vmcr, grp);
>> +	ap = pre >> (8 - nr_pre_bits);
> 
> Again here, I don't get this shift.
> 
>> +	apr = ap / 32;
>> +
>> +	val = __vgic_v3_read_ap1rn(apr);
>> +	__vgic_v3_write_ap1rn(val | BIT(ap % 32), apr);
> 
> How are we sure this is a group 1 interrupt here?

That's a bug, as we should definitely check grp here. Thanks for
noticing it!

>> +}
>> +
>> +static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>> +{
>> +	u64 lr_val;
>> +	u8 lr_prio, pmr;
>> +	int lr, grp;
>> +
>> +	grp = __vgic_v3_get_group(vcpu);
>> +
>> +	lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
>> +	if (lr < 0)
>> +		goto spurious;
>> +
>> +	if (grp != !!(lr_val & ICH_LR_GROUP))
>> +		goto spurious;
>> +
>> +	pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
>> +	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
>> +	if (pmr <= lr_prio)
>> +		goto spurious;
>> +
>> +	if (__vgic_v3_get_highest_active_priority() <= lr_prio)
>> +		goto spurious;
>> +
>> +	lr_val &= ~ICH_LR_STATE;
>> +	/* No active state for LPIs */
>> +	if ((lr_val & ICH_LR_VIRTUAL_ID_MASK) <= VGIC_MAX_SPI)
>> +		lr_val |= ICH_LR_ACTIVE_BIT;
>> +	__gic_v3_set_lr(lr_val, lr);
>> +	__vgic_v3_set_active_priority(lr_prio, vmcr, grp);
>> +	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
>> +	return;
>> +
>> +spurious:
>> +	vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS);
>> +}
>> +
>>  static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>>  {
>>  	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
>> @@ -459,6 +606,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>>  	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
>>  
>>  	switch (sysreg) {
>> +	case SYS_ICC_IAR1_EL1:
>> +		fn = __vgic_v3_read_iar;
>> +		break;
> 
> So we don't provide a write-ignore function here because we rely on the
> hardware to always trap that at EL1 instead?
> 
> I remember we discussed this before, but I don't remember if the
> conclusion was that this is 100% safe.

A properly designed CPU would UNDEF at EL1. I'm happy to try and detect
broken failing implementations here, but I'm not sure of what to do, as
we're not in the best context to handle this. We could continue exiting
to EL1 and handle things there...

Thanks,

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

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

* Re: [PATCH v2 08/25] KVM: arm64: vgic-v3: Add ICV_EOIR1_EL1 handler
  2017-06-05 10:32     ` Christoffer Dall
@ 2017-06-05 11:00       ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-05 11:00 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On 05/06/17 11:32, Christoffer Dall wrote:
> On Thu, Jun 01, 2017 at 11:21:00AM +0100, Marc Zyngier wrote:
>> Add a handler for writing the guest's view of the ICC_EOIR1_EL1
>> register. This involves dropping the priority of the interrupt,
>> and deactivating it if required (EOImode == 0).
>>
>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  include/linux/irqchip/arm-gic-v3.h |   2 +
>>  virt/kvm/arm/hyp/vgic-v3-sr.c      | 121 +++++++++++++++++++++++++++++++++++++
>>  2 files changed, 123 insertions(+)
>>
>> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
>> index 401db585a534..e50ce5d416a3 100644
>> --- a/include/linux/irqchip/arm-gic-v3.h
>> +++ b/include/linux/irqchip/arm-gic-v3.h
>> @@ -417,6 +417,8 @@
>>  
>>  #define ICH_HCR_EN			(1 << 0)
>>  #define ICH_HCR_UIE			(1 << 1)
>> +#define ICH_HCR_EOIcount_SHIFT		27
>> +#define ICH_HCR_EOIcount_MASK		(0x1f << ICH_HCR_EOIcount_SHIFT)
>>  
>>  #define ICH_VMCR_CBPR_SHIFT		4
>>  #define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
>> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> index 16a2eadc7a5c..3f04122a5d4d 100644
>> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
>> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> @@ -426,6 +426,26 @@ static int __hyp_text __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu,
>>  	return lr;
>>  }
>>  
>> +static int __hyp_text __vgic_v3_find_active_lr(struct kvm_vcpu *vcpu,
>> +					       int intid, u64 *lr_val)
>> +{
>> +	unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
>> +	int i;
>> +
>> +	for (i = 0; i < used_lrs; i++) {
>> +		u64 val = __gic_v3_get_lr(i);
>> +
>> +		if ((val & ICH_LR_VIRTUAL_ID_MASK) == intid &&
>> +		    (val & ICH_LR_ACTIVE_BIT)) {
>> +			*lr_val = val;
>> +			return i;
>> +		}
>> +	}
>> +
>> +	*lr_val = ICC_IAR1_EL1_SPURIOUS;
>> +	return -1;
>> +}
>> +
>>  static int __hyp_text __vgic_v3_get_highest_active_priority(void)
>>  {
>>  	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
>> @@ -506,6 +526,45 @@ static void __hyp_text __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp)
>>  	__vgic_v3_write_ap1rn(val | BIT(ap % 32), apr);
>>  }
>>  
>> +static int __hyp_text __vgic_v3_clear_highest_active_priority(void)
>> +{
>> +	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
>> +	u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
>> +	u32 hap = 0;
>> +	int i;
>> +
>> +	for (i = 0; i < nr_apr_regs; i++) {
>> +		u32 ap0, ap1;
>> +		int c0, c1;
>> +
>> +		ap0 = __vgic_v3_read_ap0rn(i);
>> +		ap1 = __vgic_v3_read_ap1rn(i);
> 
> so reading a group 1 interrupt from the IAR and writing that value back
> to the EOIR1_EL1 register can somehow clear the priority of a group 0
> interrupt?

If you properly nest the IAR and EOI, nothing bad will happen (group
priorities are not supposed to overlap). If you decide to do weird
things, you'll be in UNPREDICTABLE territory, and some interrupts can be
left active while you deactivate the wrong one.

> Or did you just want a generic function that does what it's supposed to
> regardless of which register was written to etc.?

That's the goal indeed.

> 
>> +		if (!ap0 && !ap1) {
>> +			hap += 32;
>> +			continue;
>> +		}
>> +
>> +		c0 = ap0 ? __ffs(ap0) : 32;
>> +		c1 = ap1 ? __ffs(ap1) : 32;
>> +
>> +		/* Always clear the LSB, which is the highest priority */
>> +		if (c0 < c1) {
>> +			ap0 &= ~BIT(c0);
>> +			__vgic_v3_write_ap0rn(ap0, i);
>> +			hap += c0;
>> +		} else {
>> +			ap1 &= ~BIT(c1);
>> +			__vgic_v3_write_ap1rn(ap1, i);
>> +			hap += c1;
> 
> Can we ever have a situation where c0 == c1?  And in that case, should
> you prioritize clearing the group 1 apr ?

You shouldn't ever have this case. The spec says:

"Having the bit corresponding to a priority set to 1 in both
ICH_AP0R<n>_EL2 and ICH_AP1R<n>_EL2 might result in UNPREDICTABLE
behavior of the interrupt prioritization system for virtual interrupts."

>> +		}
>> +
>> +		/* Rescale to 8 bits of priority */
>> +		return hap << (8 - nr_pre_bits);
>> +	}
>> +
>> +	return GICv3_IDLE_PRIORITY;
>> +}
>> +
>>  static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>>  {
>>  	u64 lr_val;
>> @@ -542,6 +601,65 @@ static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int r
>>  	vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS);
>>  }
>>  
>> +static void __hyp_text __vgic_v3_clear_active_lr(int lr, u64 lr_val)
>> +{
>> +	lr_val &= ~ICH_LR_ACTIVE_BIT;
>> +	if (lr_val & ICH_LR_HW) {
>> +		u32 pid;
>> +
>> +		pid = (lr_val & ICH_LR_PHYS_ID_MASK) >> ICH_LR_PHYS_ID_SHIFT;
>> +		gic_write_dir(pid);
> 
> Yikes, scary.  I can't think of this breaking anything.  But, scary.

I know. a (slightly) less scary approach would be to go all the way back
to EL1 and to the DIR write there, but I don't thing this buys us
anything but wasted cycles...

> 
>> +	}
>> +
>> +	__gic_v3_set_lr(lr_val, lr);
>> +}
>> +
>> +static void __hyp_text __vgic_v3_bump_eoicount(void)
>> +{
>> +	u32 hcr;
>> +
>> +	hcr = read_gicreg(ICH_HCR_EL2);
>> +	hcr += 1 << ICH_HCR_EOIcount_SHIFT;
>> +	write_gicreg(hcr, ICH_HCR_EL2);
>> +}
>> +
>> +static void __hyp_text __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>> +{
>> +	u32 vid = vcpu_get_reg(vcpu, rt);
>> +	u64 lr_val;
>> +	u8 lr_prio, act_prio;
>> +	int lr, grp;
>> +
>> +	grp = __vgic_v3_get_group(vcpu);
>> +
>> +	/* Drop priority in any case */
>> +	act_prio = __vgic_v3_clear_highest_active_priority();
>> +
>> +	/* If EOIing an LPI, no deactivate to be performed */
>> +	if (vid >= VGIC_MIN_LPI)
>> +		return;
>> +
>> +	/* EOImode == 1, nothing to be done here */
>> +	if (vmcr & ICH_VMCR_EOIM_MASK)
>> +		return;
>> +
>> +	lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val);
>> +	if (lr == -1) {
>> +		__vgic_v3_bump_eoicount();
>> +		return;
>> +	}
>> +
>> +	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
>> +
>> +	/* If priorities or group do not match, the guest has fscked-up. */
>> +	if (grp != !!(lr_val & ICH_LR_GROUP) ||
>> +	    __vgic_v3_pri_to_pre(lr_prio, vmcr, grp) != act_prio)
>> +		return;
> 
> Since we've cleared the highest priority above, is there any way for the
> guest to recover from this, or do this particular (v)GIC implementation
> have the implementation defined behavior of a write with something else
> than the last valid read from the IAR of the same group to the EOIR
> means that the system is toast?

The only way to recover from such a situation from a guest PoV is to
write its APRs to zero, turn everything off, reset the whole GIC, and
restart from scratch. Not pleasant...

Thanks,

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

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

* [PATCH v2 08/25] KVM: arm64: vgic-v3: Add ICV_EOIR1_EL1 handler
@ 2017-06-05 11:00       ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-05 11:00 UTC (permalink / raw)
  To: linux-arm-kernel

On 05/06/17 11:32, Christoffer Dall wrote:
> On Thu, Jun 01, 2017 at 11:21:00AM +0100, Marc Zyngier wrote:
>> Add a handler for writing the guest's view of the ICC_EOIR1_EL1
>> register. This involves dropping the priority of the interrupt,
>> and deactivating it if required (EOImode == 0).
>>
>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  include/linux/irqchip/arm-gic-v3.h |   2 +
>>  virt/kvm/arm/hyp/vgic-v3-sr.c      | 121 +++++++++++++++++++++++++++++++++++++
>>  2 files changed, 123 insertions(+)
>>
>> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
>> index 401db585a534..e50ce5d416a3 100644
>> --- a/include/linux/irqchip/arm-gic-v3.h
>> +++ b/include/linux/irqchip/arm-gic-v3.h
>> @@ -417,6 +417,8 @@
>>  
>>  #define ICH_HCR_EN			(1 << 0)
>>  #define ICH_HCR_UIE			(1 << 1)
>> +#define ICH_HCR_EOIcount_SHIFT		27
>> +#define ICH_HCR_EOIcount_MASK		(0x1f << ICH_HCR_EOIcount_SHIFT)
>>  
>>  #define ICH_VMCR_CBPR_SHIFT		4
>>  #define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
>> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> index 16a2eadc7a5c..3f04122a5d4d 100644
>> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
>> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> @@ -426,6 +426,26 @@ static int __hyp_text __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu,
>>  	return lr;
>>  }
>>  
>> +static int __hyp_text __vgic_v3_find_active_lr(struct kvm_vcpu *vcpu,
>> +					       int intid, u64 *lr_val)
>> +{
>> +	unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
>> +	int i;
>> +
>> +	for (i = 0; i < used_lrs; i++) {
>> +		u64 val = __gic_v3_get_lr(i);
>> +
>> +		if ((val & ICH_LR_VIRTUAL_ID_MASK) == intid &&
>> +		    (val & ICH_LR_ACTIVE_BIT)) {
>> +			*lr_val = val;
>> +			return i;
>> +		}
>> +	}
>> +
>> +	*lr_val = ICC_IAR1_EL1_SPURIOUS;
>> +	return -1;
>> +}
>> +
>>  static int __hyp_text __vgic_v3_get_highest_active_priority(void)
>>  {
>>  	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
>> @@ -506,6 +526,45 @@ static void __hyp_text __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp)
>>  	__vgic_v3_write_ap1rn(val | BIT(ap % 32), apr);
>>  }
>>  
>> +static int __hyp_text __vgic_v3_clear_highest_active_priority(void)
>> +{
>> +	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
>> +	u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
>> +	u32 hap = 0;
>> +	int i;
>> +
>> +	for (i = 0; i < nr_apr_regs; i++) {
>> +		u32 ap0, ap1;
>> +		int c0, c1;
>> +
>> +		ap0 = __vgic_v3_read_ap0rn(i);
>> +		ap1 = __vgic_v3_read_ap1rn(i);
> 
> so reading a group 1 interrupt from the IAR and writing that value back
> to the EOIR1_EL1 register can somehow clear the priority of a group 0
> interrupt?

If you properly nest the IAR and EOI, nothing bad will happen (group
priorities are not supposed to overlap). If you decide to do weird
things, you'll be in UNPREDICTABLE territory, and some interrupts can be
left active while you deactivate the wrong one.

> Or did you just want a generic function that does what it's supposed to
> regardless of which register was written to etc.?

That's the goal indeed.

> 
>> +		if (!ap0 && !ap1) {
>> +			hap += 32;
>> +			continue;
>> +		}
>> +
>> +		c0 = ap0 ? __ffs(ap0) : 32;
>> +		c1 = ap1 ? __ffs(ap1) : 32;
>> +
>> +		/* Always clear the LSB, which is the highest priority */
>> +		if (c0 < c1) {
>> +			ap0 &= ~BIT(c0);
>> +			__vgic_v3_write_ap0rn(ap0, i);
>> +			hap += c0;
>> +		} else {
>> +			ap1 &= ~BIT(c1);
>> +			__vgic_v3_write_ap1rn(ap1, i);
>> +			hap += c1;
> 
> Can we ever have a situation where c0 == c1?  And in that case, should
> you prioritize clearing the group 1 apr ?

You shouldn't ever have this case. The spec says:

"Having the bit corresponding to a priority set to 1 in both
ICH_AP0R<n>_EL2 and ICH_AP1R<n>_EL2 might result in UNPREDICTABLE
behavior of the interrupt prioritization system for virtual interrupts."

>> +		}
>> +
>> +		/* Rescale to 8 bits of priority */
>> +		return hap << (8 - nr_pre_bits);
>> +	}
>> +
>> +	return GICv3_IDLE_PRIORITY;
>> +}
>> +
>>  static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>>  {
>>  	u64 lr_val;
>> @@ -542,6 +601,65 @@ static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int r
>>  	vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS);
>>  }
>>  
>> +static void __hyp_text __vgic_v3_clear_active_lr(int lr, u64 lr_val)
>> +{
>> +	lr_val &= ~ICH_LR_ACTIVE_BIT;
>> +	if (lr_val & ICH_LR_HW) {
>> +		u32 pid;
>> +
>> +		pid = (lr_val & ICH_LR_PHYS_ID_MASK) >> ICH_LR_PHYS_ID_SHIFT;
>> +		gic_write_dir(pid);
> 
> Yikes, scary.  I can't think of this breaking anything.  But, scary.

I know. a (slightly) less scary approach would be to go all the way back
to EL1 and to the DIR write there, but I don't thing this buys us
anything but wasted cycles...

> 
>> +	}
>> +
>> +	__gic_v3_set_lr(lr_val, lr);
>> +}
>> +
>> +static void __hyp_text __vgic_v3_bump_eoicount(void)
>> +{
>> +	u32 hcr;
>> +
>> +	hcr = read_gicreg(ICH_HCR_EL2);
>> +	hcr += 1 << ICH_HCR_EOIcount_SHIFT;
>> +	write_gicreg(hcr, ICH_HCR_EL2);
>> +}
>> +
>> +static void __hyp_text __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>> +{
>> +	u32 vid = vcpu_get_reg(vcpu, rt);
>> +	u64 lr_val;
>> +	u8 lr_prio, act_prio;
>> +	int lr, grp;
>> +
>> +	grp = __vgic_v3_get_group(vcpu);
>> +
>> +	/* Drop priority in any case */
>> +	act_prio = __vgic_v3_clear_highest_active_priority();
>> +
>> +	/* If EOIing an LPI, no deactivate to be performed */
>> +	if (vid >= VGIC_MIN_LPI)
>> +		return;
>> +
>> +	/* EOImode == 1, nothing to be done here */
>> +	if (vmcr & ICH_VMCR_EOIM_MASK)
>> +		return;
>> +
>> +	lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val);
>> +	if (lr == -1) {
>> +		__vgic_v3_bump_eoicount();
>> +		return;
>> +	}
>> +
>> +	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
>> +
>> +	/* If priorities or group do not match, the guest has fscked-up. */
>> +	if (grp != !!(lr_val & ICH_LR_GROUP) ||
>> +	    __vgic_v3_pri_to_pre(lr_prio, vmcr, grp) != act_prio)
>> +		return;
> 
> Since we've cleared the highest priority above, is there any way for the
> guest to recover from this, or do this particular (v)GIC implementation
> have the implementation defined behavior of a write with something else
> than the last valid read from the IAR of the same group to the EOIR
> means that the system is toast?

The only way to recover from such a situation from a guest PoV is to
write its APRs to zero, turn everything off, reset the whole GIC, and
restart from scratch. Not pleasant...

Thanks,

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

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

* Re: [PATCH v2 05/25] KVM: arm64: vgic-v3: Add ICV_BPR1_EL1 handler
  2017-06-05  9:58       ` Marc Zyngier
@ 2017-06-06  9:41         ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06  9:41 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter,
	linux-arm-kernel, kvmarm

On Mon, Jun 05, 2017 at 10:58:57AM +0100, Marc Zyngier wrote:
> On 04/06/17 21:25, Christoffer Dall wrote:
> > On Thu, Jun 01, 2017 at 11:20:57AM +0100, Marc Zyngier wrote:
> >> Add a handler for reading/writing the guest's view of the ICC_BPR1_EL1
> >> register, which is located in the ICH_VMCR_EL2.BPR1 field.
> >>
> >> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> ---
> >>  virt/kvm/arm/hyp/vgic-v3-sr.c | 51 +++++++++++++++++++++++++++++++++++++++++++
> >>  1 file changed, 51 insertions(+)
> >>
> >> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> index 943bf11252d9..6254eaf72a77 100644
> >> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> @@ -375,6 +375,51 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
> >>  
> >>  #ifdef CONFIG_ARM64
> >>  
> >> +static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
> >> +{
> >> +	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
> >> +}
> >> +
> >> +static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
> >> +{
> >> +	unsigned int bpr;
> >> +
> >> +	if (vmcr & ICH_VMCR_CBPR_MASK) {
> >> +		bpr = __vgic_v3_get_bpr0(vmcr);
> >> +		if (bpr < 7)
> >> +			bpr++;
> >> +	} else {
> >> +		bpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
> >> +	}
> >> +
> >> +	return bpr;
> >> +}
> >> +
> >> +static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >> +{
> >> +	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
> >> +}
> >> +
> >> +static void __hyp_text __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >> +{
> >> +	u64 val = vcpu_get_reg(vcpu, rt);
> >> +	u8 bpr_min = 8 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> > 
> > I can't seem to find where this behavior is documented, is it that 8 is
> > the theoretical max, and it's the upper preemption levels that apply, so
> > it must be 8 - number supported?
> 
> I took inspiration from the VPriorityGroup() helper in the GICv3
> pseudocode. You can also deduct this from the table described in the
> ICC_BPR0_EL1 documentation, though that's admittedly not very clear.
> 

Ah, yes, now I understand this. Since you can at most support
ICH_VTR_EL2.PREbits than the minimal value must be one that doesn't
define more preemmption levels.  I don't know why this was so hard for
me to realize.

Thanks,
-Christoffer

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

* [PATCH v2 05/25] KVM: arm64: vgic-v3: Add ICV_BPR1_EL1 handler
@ 2017-06-06  9:41         ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06  9:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jun 05, 2017 at 10:58:57AM +0100, Marc Zyngier wrote:
> On 04/06/17 21:25, Christoffer Dall wrote:
> > On Thu, Jun 01, 2017 at 11:20:57AM +0100, Marc Zyngier wrote:
> >> Add a handler for reading/writing the guest's view of the ICC_BPR1_EL1
> >> register, which is located in the ICH_VMCR_EL2.BPR1 field.
> >>
> >> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> ---
> >>  virt/kvm/arm/hyp/vgic-v3-sr.c | 51 +++++++++++++++++++++++++++++++++++++++++++
> >>  1 file changed, 51 insertions(+)
> >>
> >> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> index 943bf11252d9..6254eaf72a77 100644
> >> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> @@ -375,6 +375,51 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
> >>  
> >>  #ifdef CONFIG_ARM64
> >>  
> >> +static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
> >> +{
> >> +	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
> >> +}
> >> +
> >> +static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
> >> +{
> >> +	unsigned int bpr;
> >> +
> >> +	if (vmcr & ICH_VMCR_CBPR_MASK) {
> >> +		bpr = __vgic_v3_get_bpr0(vmcr);
> >> +		if (bpr < 7)
> >> +			bpr++;
> >> +	} else {
> >> +		bpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT;
> >> +	}
> >> +
> >> +	return bpr;
> >> +}
> >> +
> >> +static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >> +{
> >> +	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
> >> +}
> >> +
> >> +static void __hyp_text __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >> +{
> >> +	u64 val = vcpu_get_reg(vcpu, rt);
> >> +	u8 bpr_min = 8 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> > 
> > I can't seem to find where this behavior is documented, is it that 8 is
> > the theoretical max, and it's the upper preemption levels that apply, so
> > it must be 8 - number supported?
> 
> I took inspiration from the VPriorityGroup() helper in the GICv3
> pseudocode. You can also deduct this from the table described in the
> ICC_BPR0_EL1 documentation, though that's admittedly not very clear.
> 

Ah, yes, now I understand this. Since you can at most support
ICH_VTR_EL2.PREbits than the minimal value must be one that doesn't
define more preemmption levels.  I don't know why this was so hard for
me to realize.

Thanks,
-Christoffer

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

* Re: [PATCH v2 07/25] KVM: arm64: vgic-v3: Add ICV_IAR1_EL1 handler
  2017-06-05 10:33       ` Marc Zyngier
@ 2017-06-06 11:09         ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 11:09 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On Mon, Jun 05, 2017 at 11:33:52AM +0100, Marc Zyngier wrote:
> On 05/06/17 10:21, Christoffer Dall wrote:
> > On Thu, Jun 01, 2017 at 11:20:59AM +0100, Marc Zyngier wrote:
> >> Add a handler for reading the guest's view of the ICC_IAR1_EL1
> >> register. This involves finding the highest priority Group-1
> >> interrupt, checking against both PMR and the active group
> >> priority, activating the interrupt and setting the group
> >> priority as active.
> >>
> >> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> ---
> >>  include/linux/irqchip/arm-gic-v3.h |   1 +
> >>  virt/kvm/arm/hyp/vgic-v3-sr.c      | 150 +++++++++++++++++++++++++++++++++++++
> >>  2 files changed, 151 insertions(+)
> >>
> >> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> >> index fffb91202bc9..401db585a534 100644
> >> --- a/include/linux/irqchip/arm-gic-v3.h
> >> +++ b/include/linux/irqchip/arm-gic-v3.h
> >> @@ -405,6 +405,7 @@
> >>  #define ICH_LR_PHYS_ID_SHIFT		32
> >>  #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
> >>  #define ICH_LR_PRIORITY_SHIFT		48
> >> +#define ICH_LR_PRIORITY_MASK		(0xffULL << ICH_LR_PRIORITY_SHIFT)
> >>  
> >>  /* These are for GICv2 emulation only */
> >>  #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
> >> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> index 168539dfd0b9..16a2eadc7a5c 100644
> >> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> @@ -24,6 +24,7 @@
> >>  
> >>  #define vtr_to_max_lr_idx(v)		((v) & 0xf)
> >>  #define vtr_to_nr_pre_bits(v)		(((u32)(v) >> 26) + 1)
> >> +#define vtr_to_nr_apr_regs(v)		(1 << (vtr_to_nr_pre_bits(v) - 5))
> >>  
> >>  static u64 __hyp_text __gic_v3_get_lr(unsigned int lr)
> >>  {
> >> @@ -375,6 +376,79 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
> >>  
> >>  #ifdef CONFIG_ARM64
> >>  
> >> +static int __hyp_text __vgic_v3_get_group(struct kvm_vcpu *vcpu)
> >> +{
> >> +	u32 esr = kvm_vcpu_get_hsr(vcpu);
> >> +	u8 crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT;
> >> +
> >> +	return crm != 8;
> >> +}
> >> +
> >> +#define GICv3_IDLE_PRIORITY	0xff
> >> +
> >> +static int __hyp_text __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu,
> >> +						    u32 vmcr,
> >> +						    u64 *lr_val)
> >> +{
> >> +	unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
> >> +	u8 priority = GICv3_IDLE_PRIORITY;
> >> +	int i, lr = -1;
> >> +
> >> +	for (i = 0; i < used_lrs; i++) {
> >> +		u64 val = __gic_v3_get_lr(i);
> >> +		u8 lr_prio = (val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
> >> +
> >> +		/* Not pending in the state? */
> >> +		if ((val & ICH_LR_STATE) != ICH_LR_PENDING_BIT)
> >> +			continue;
> >> +
> >> +		/* Group-0 interrupt, but Group-0 disabled? */
> >> +		if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG0_MASK))
> >> +			continue;
> >> +
> >> +		/* Group-1 interrupt, but Group-1 disabled? */
> >> +		if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG1_MASK))
> >> +			continue;
> >> +
> >> +		/* Not the highest priority? */
> >> +		if (lr_prio >= priority)
> >> +			continue;
> >> +
> >> +		/* This is a candidate */
> >> +		priority = lr_prio;
> >> +		*lr_val = val;
> >> +		lr = i;
> >> +	}
> >> +
> >> +	if (lr == -1)
> >> +		*lr_val = ICC_IAR1_EL1_SPURIOUS;
> >> +
> >> +	return lr;
> >> +}
> >> +
> >> +static int __hyp_text __vgic_v3_get_highest_active_priority(void)
> >> +{
> >> +	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> >> +	u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
> >> +	u32 hap = 0;
> >> +	int i;
> >> +
> >> +	for (i = 0; i < nr_apr_regs; i++) {
> >> +		u32 val;
> >> +
> >> +		val  = __vgic_v3_read_ap0rn(i);
> >> +		val |= __vgic_v3_read_ap1rn(i);
> >> +		if (!val) {
> >> +			hap += 32;
> >> +			continue;
> >> +		}
> >> +
> >> +		return (hap + __ffs(val)) << (8 - nr_pre_bits);
> > 
> > I don't understand this shift, and I think I asked about it before, so
> > maybe if it's a reused concept we can use a static inline or at least
> > provide a comment?
> 
> I tried to explain it in my reply to your comment on patch #5. Can
> definitely make that a helper. I think part of the confusion is that
> this constant is used in a number of ways to express the conversion
> between a preemption level and a priority.
> 

ok, I understand it now, but it's weird that we use 8 as a constant here
(which applied to both group 0 and group 1) but 7 and 8, respecitvely,
for the writes to the bpr0.

I understand that these two concepts are actually independent and
loosely related, so maybe adding something like this would help:

		/*
		 * The ICH_AP0Rn_EL2 and ICH_AP1Rn_EL2 registers contain
		 * the active priority levels for this VCPU for the
		 * maximum number of supported priority levels, and we
		 * return the full priority level only if the BPR is
		 * programmed to its minimum, otherwise we return a
		 * combination of the priority level and subpriority, as
		 * determined by the setting of the BPR, but without the
		 * full subpriority.
		 */

Maybe this is wrong and will just confuse people more?

> >> +	}
> >> +
> >> +	return GICv3_IDLE_PRIORITY;
> >> +}
> >> +
> >>  static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
> >>  {
> >>  	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
> >> @@ -395,6 +469,79 @@ static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
> >>  	return bpr;
> >>  }
> >>  
> >> +/*
> >> + * Convert a priority to a preemption level, taking the relevant BPR
> >> + * into account by zeroing the sub-priority bits.
> >> + */
> >> +static u8 __hyp_text __vgic_v3_pri_to_pre(u8 pri, u32 vmcr, int grp)
> >> +{
> >> +	unsigned int bpr;
> >> +
> >> +	if (!grp)
> >> +		bpr = __vgic_v3_get_bpr0(vmcr) + 1;
> >> +	else
> >> +		bpr = __vgic_v3_get_bpr1(vmcr);
> >> +
> >> +	return pri & (GENMASK(7, 0) << bpr);
> >> +}
> >> +
> >> +/*
> >> + * The priority value is independent of any of the BPR values, so we
> >> + * normalize it using nr_pre_bits. This guarantees that no matter what
> >> + * the guest does with its BPR, we can always set/get the same value
> >> + * of a priority.
> >> + */
> >> +static void __hyp_text __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp)
> >> +{
> >> +	u8 nr_pre_bits, pre, ap;
> >> +	u32 val;
> >> +	int apr;
> >> +
> >> +	nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> >> +	pre = __vgic_v3_pri_to_pre(pri, vmcr, grp);
> >> +	ap = pre >> (8 - nr_pre_bits);
> > 
> > Again here, I don't get this shift.
> > 
> >> +	apr = ap / 32;
> >> +
> >> +	val = __vgic_v3_read_ap1rn(apr);
> >> +	__vgic_v3_write_ap1rn(val | BIT(ap % 32), apr);
> > 
> > How are we sure this is a group 1 interrupt here?
> 
> That's a bug, as we should definitely check grp here. Thanks for
> noticing it!
> 

Sure.  Also, the spec says "Writing to these registers with any value
other than the last read value of the register (or 0x00000000 for a
newly set up virtual machine) can result in UNPREDICTABLE behavior of
the virtual interrupt prioritization system allowing either: ...".  Does
that just translate to "You should know what you're doing", or could we
be breaking something here?

> >> +}
> >> +
> >> +static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >> +{
> >> +	u64 lr_val;
> >> +	u8 lr_prio, pmr;
> >> +	int lr, grp;
> >> +
> >> +	grp = __vgic_v3_get_group(vcpu);
> >> +
> >> +	lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
> >> +	if (lr < 0)
> >> +		goto spurious;
> >> +
> >> +	if (grp != !!(lr_val & ICH_LR_GROUP))
> >> +		goto spurious;
> >> +
> >> +	pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
> >> +	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
> >> +	if (pmr <= lr_prio)
> >> +		goto spurious;
> >> +
> >> +	if (__vgic_v3_get_highest_active_priority() <= lr_prio)
> >> +		goto spurious;

Based on what I wrote above, don't you need to consider the actual
setting of the BPR here?

For example, if __vgic_v3_get_highest_active_priority() == 100.10 and
lr_prio == 100.09  (BPR == 5 for a group 1 interrupt) then you'll
compare 10010 <= 10009, you won't take the branch and you'll let the
guest ack another interrupt at the same-and-already-active preemption
level.

Or am I again misunderstandin how this whole thing works?

> >> +
> >> +	lr_val &= ~ICH_LR_STATE;
> >> +	/* No active state for LPIs */
> >> +	if ((lr_val & ICH_LR_VIRTUAL_ID_MASK) <= VGIC_MAX_SPI)
> >> +		lr_val |= ICH_LR_ACTIVE_BIT;
> >> +	__gic_v3_set_lr(lr_val, lr);
> >> +	__vgic_v3_set_active_priority(lr_prio, vmcr, grp);
> >> +	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
> >> +	return;
> >> +
> >> +spurious:
> >> +	vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS);
> >> +}
> >> +
> >>  static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >>  {
> >>  	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
> >> @@ -459,6 +606,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
> >>  	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
> >>  
> >>  	switch (sysreg) {
> >> +	case SYS_ICC_IAR1_EL1:
> >> +		fn = __vgic_v3_read_iar;
> >> +		break;
> > 
> > So we don't provide a write-ignore function here because we rely on the
> > hardware to always trap that at EL1 instead?
> > 
> > I remember we discussed this before, but I don't remember if the
> > conclusion was that this is 100% safe.
> 
> A properly designed CPU would UNDEF at EL1. I'm happy to try and detect
> broken failing implementations here, but I'm not sure of what to do, as
> we're not in the best context to handle this. We could continue exiting
> to EL1 and handle things there...
> 

I feel like we decided that other parts of KVM relies on this being
implemented correctly, so maybe this is not the place to begin being
overly cautious about things.

That said, having a path back to EL1 where we can print stuff and
create warnings, may not be an entirely bad idea.

Thanks,
-Christoffer

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

* [PATCH v2 07/25] KVM: arm64: vgic-v3: Add ICV_IAR1_EL1 handler
@ 2017-06-06 11:09         ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 11:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jun 05, 2017 at 11:33:52AM +0100, Marc Zyngier wrote:
> On 05/06/17 10:21, Christoffer Dall wrote:
> > On Thu, Jun 01, 2017 at 11:20:59AM +0100, Marc Zyngier wrote:
> >> Add a handler for reading the guest's view of the ICC_IAR1_EL1
> >> register. This involves finding the highest priority Group-1
> >> interrupt, checking against both PMR and the active group
> >> priority, activating the interrupt and setting the group
> >> priority as active.
> >>
> >> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> ---
> >>  include/linux/irqchip/arm-gic-v3.h |   1 +
> >>  virt/kvm/arm/hyp/vgic-v3-sr.c      | 150 +++++++++++++++++++++++++++++++++++++
> >>  2 files changed, 151 insertions(+)
> >>
> >> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> >> index fffb91202bc9..401db585a534 100644
> >> --- a/include/linux/irqchip/arm-gic-v3.h
> >> +++ b/include/linux/irqchip/arm-gic-v3.h
> >> @@ -405,6 +405,7 @@
> >>  #define ICH_LR_PHYS_ID_SHIFT		32
> >>  #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
> >>  #define ICH_LR_PRIORITY_SHIFT		48
> >> +#define ICH_LR_PRIORITY_MASK		(0xffULL << ICH_LR_PRIORITY_SHIFT)
> >>  
> >>  /* These are for GICv2 emulation only */
> >>  #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
> >> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> index 168539dfd0b9..16a2eadc7a5c 100644
> >> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> @@ -24,6 +24,7 @@
> >>  
> >>  #define vtr_to_max_lr_idx(v)		((v) & 0xf)
> >>  #define vtr_to_nr_pre_bits(v)		(((u32)(v) >> 26) + 1)
> >> +#define vtr_to_nr_apr_regs(v)		(1 << (vtr_to_nr_pre_bits(v) - 5))
> >>  
> >>  static u64 __hyp_text __gic_v3_get_lr(unsigned int lr)
> >>  {
> >> @@ -375,6 +376,79 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
> >>  
> >>  #ifdef CONFIG_ARM64
> >>  
> >> +static int __hyp_text __vgic_v3_get_group(struct kvm_vcpu *vcpu)
> >> +{
> >> +	u32 esr = kvm_vcpu_get_hsr(vcpu);
> >> +	u8 crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT;
> >> +
> >> +	return crm != 8;
> >> +}
> >> +
> >> +#define GICv3_IDLE_PRIORITY	0xff
> >> +
> >> +static int __hyp_text __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu,
> >> +						    u32 vmcr,
> >> +						    u64 *lr_val)
> >> +{
> >> +	unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
> >> +	u8 priority = GICv3_IDLE_PRIORITY;
> >> +	int i, lr = -1;
> >> +
> >> +	for (i = 0; i < used_lrs; i++) {
> >> +		u64 val = __gic_v3_get_lr(i);
> >> +		u8 lr_prio = (val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
> >> +
> >> +		/* Not pending in the state? */
> >> +		if ((val & ICH_LR_STATE) != ICH_LR_PENDING_BIT)
> >> +			continue;
> >> +
> >> +		/* Group-0 interrupt, but Group-0 disabled? */
> >> +		if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG0_MASK))
> >> +			continue;
> >> +
> >> +		/* Group-1 interrupt, but Group-1 disabled? */
> >> +		if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG1_MASK))
> >> +			continue;
> >> +
> >> +		/* Not the highest priority? */
> >> +		if (lr_prio >= priority)
> >> +			continue;
> >> +
> >> +		/* This is a candidate */
> >> +		priority = lr_prio;
> >> +		*lr_val = val;
> >> +		lr = i;
> >> +	}
> >> +
> >> +	if (lr == -1)
> >> +		*lr_val = ICC_IAR1_EL1_SPURIOUS;
> >> +
> >> +	return lr;
> >> +}
> >> +
> >> +static int __hyp_text __vgic_v3_get_highest_active_priority(void)
> >> +{
> >> +	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> >> +	u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
> >> +	u32 hap = 0;
> >> +	int i;
> >> +
> >> +	for (i = 0; i < nr_apr_regs; i++) {
> >> +		u32 val;
> >> +
> >> +		val  = __vgic_v3_read_ap0rn(i);
> >> +		val |= __vgic_v3_read_ap1rn(i);
> >> +		if (!val) {
> >> +			hap += 32;
> >> +			continue;
> >> +		}
> >> +
> >> +		return (hap + __ffs(val)) << (8 - nr_pre_bits);
> > 
> > I don't understand this shift, and I think I asked about it before, so
> > maybe if it's a reused concept we can use a static inline or at least
> > provide a comment?
> 
> I tried to explain it in my reply to your comment on patch #5. Can
> definitely make that a helper. I think part of the confusion is that
> this constant is used in a number of ways to express the conversion
> between a preemption level and a priority.
> 

ok, I understand it now, but it's weird that we use 8 as a constant here
(which applied to both group 0 and group 1) but 7 and 8, respecitvely,
for the writes to the bpr0.

I understand that these two concepts are actually independent and
loosely related, so maybe adding something like this would help:

		/*
		 * The ICH_AP0Rn_EL2 and ICH_AP1Rn_EL2 registers contain
		 * the active priority levels for this VCPU for the
		 * maximum number of supported priority levels, and we
		 * return the full priority level only if the BPR is
		 * programmed to its minimum, otherwise we return a
		 * combination of the priority level and subpriority, as
		 * determined by the setting of the BPR, but without the
		 * full subpriority.
		 */

Maybe this is wrong and will just confuse people more?

> >> +	}
> >> +
> >> +	return GICv3_IDLE_PRIORITY;
> >> +}
> >> +
> >>  static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
> >>  {
> >>  	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
> >> @@ -395,6 +469,79 @@ static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
> >>  	return bpr;
> >>  }
> >>  
> >> +/*
> >> + * Convert a priority to a preemption level, taking the relevant BPR
> >> + * into account by zeroing the sub-priority bits.
> >> + */
> >> +static u8 __hyp_text __vgic_v3_pri_to_pre(u8 pri, u32 vmcr, int grp)
> >> +{
> >> +	unsigned int bpr;
> >> +
> >> +	if (!grp)
> >> +		bpr = __vgic_v3_get_bpr0(vmcr) + 1;
> >> +	else
> >> +		bpr = __vgic_v3_get_bpr1(vmcr);
> >> +
> >> +	return pri & (GENMASK(7, 0) << bpr);
> >> +}
> >> +
> >> +/*
> >> + * The priority value is independent of any of the BPR values, so we
> >> + * normalize it using nr_pre_bits. This guarantees that no matter what
> >> + * the guest does with its BPR, we can always set/get the same value
> >> + * of a priority.
> >> + */
> >> +static void __hyp_text __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp)
> >> +{
> >> +	u8 nr_pre_bits, pre, ap;
> >> +	u32 val;
> >> +	int apr;
> >> +
> >> +	nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> >> +	pre = __vgic_v3_pri_to_pre(pri, vmcr, grp);
> >> +	ap = pre >> (8 - nr_pre_bits);
> > 
> > Again here, I don't get this shift.
> > 
> >> +	apr = ap / 32;
> >> +
> >> +	val = __vgic_v3_read_ap1rn(apr);
> >> +	__vgic_v3_write_ap1rn(val | BIT(ap % 32), apr);
> > 
> > How are we sure this is a group 1 interrupt here?
> 
> That's a bug, as we should definitely check grp here. Thanks for
> noticing it!
> 

Sure.  Also, the spec says "Writing to these registers with any value
other than the last read value of the register (or 0x00000000 for a
newly set up virtual machine) can result in UNPREDICTABLE behavior of
the virtual interrupt prioritization system allowing either: ...".  Does
that just translate to "You should know what you're doing", or could we
be breaking something here?

> >> +}
> >> +
> >> +static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >> +{
> >> +	u64 lr_val;
> >> +	u8 lr_prio, pmr;
> >> +	int lr, grp;
> >> +
> >> +	grp = __vgic_v3_get_group(vcpu);
> >> +
> >> +	lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
> >> +	if (lr < 0)
> >> +		goto spurious;
> >> +
> >> +	if (grp != !!(lr_val & ICH_LR_GROUP))
> >> +		goto spurious;
> >> +
> >> +	pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
> >> +	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
> >> +	if (pmr <= lr_prio)
> >> +		goto spurious;
> >> +
> >> +	if (__vgic_v3_get_highest_active_priority() <= lr_prio)
> >> +		goto spurious;

Based on what I wrote above, don't you need to consider the actual
setting of the BPR here?

For example, if __vgic_v3_get_highest_active_priority() == 100.10 and
lr_prio == 100.09  (BPR == 5 for a group 1 interrupt) then you'll
compare 10010 <= 10009, you won't take the branch and you'll let the
guest ack another interrupt@the same-and-already-active preemption
level.

Or am I again misunderstandin how this whole thing works?

> >> +
> >> +	lr_val &= ~ICH_LR_STATE;
> >> +	/* No active state for LPIs */
> >> +	if ((lr_val & ICH_LR_VIRTUAL_ID_MASK) <= VGIC_MAX_SPI)
> >> +		lr_val |= ICH_LR_ACTIVE_BIT;
> >> +	__gic_v3_set_lr(lr_val, lr);
> >> +	__vgic_v3_set_active_priority(lr_prio, vmcr, grp);
> >> +	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
> >> +	return;
> >> +
> >> +spurious:
> >> +	vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS);
> >> +}
> >> +
> >>  static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >>  {
> >>  	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
> >> @@ -459,6 +606,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
> >>  	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
> >>  
> >>  	switch (sysreg) {
> >> +	case SYS_ICC_IAR1_EL1:
> >> +		fn = __vgic_v3_read_iar;
> >> +		break;
> > 
> > So we don't provide a write-ignore function here because we rely on the
> > hardware to always trap that at EL1 instead?
> > 
> > I remember we discussed this before, but I don't remember if the
> > conclusion was that this is 100% safe.
> 
> A properly designed CPU would UNDEF at EL1. I'm happy to try and detect
> broken failing implementations here, but I'm not sure of what to do, as
> we're not in the best context to handle this. We could continue exiting
> to EL1 and handle things there...
> 

I feel like we decided that other parts of KVM relies on this being
implemented correctly, so maybe this is not the place to begin being
overly cautious about things.

That said, having a path back to EL1 where we can print stuff and
create warnings, may not be an entirely bad idea.

Thanks,
-Christoffer

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

* Re: [PATCH v2 10/25] KVM: arm64: vgic-v3: Add ICV_HPPIR1_EL1 handler
  2017-06-01 10:21   ` Marc Zyngier
@ 2017-06-06 11:51     ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 11:51 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On Thu, Jun 01, 2017 at 11:21:02AM +0100, Marc Zyngier wrote:
> Add a handler for reading the guest's view of the ICV_HPPIR1_EL1
> register. This is a simple parsing of the available LRs, extracting the
> highest available interrupt.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  arch/arm64/include/asm/sysreg.h |  1 +
>  virt/kvm/arm/hyp/vgic-v3-sr.c   | 23 +++++++++++++++++++++++
>  2 files changed, 24 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index aad46b8eea5e..bd000686194a 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -185,6 +185,7 @@
>  #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
>  #define SYS_ICC_IAR1_EL1		sys_reg(3, 0, 12, 12, 0)
>  #define SYS_ICC_EOIR1_EL1		sys_reg(3, 0, 12, 12, 1)
> +#define SYS_ICC_HPPIR1_EL1		sys_reg(3, 0, 12, 12, 2)
>  #define SYS_ICC_BPR1_EL1		sys_reg(3, 0, 12, 12, 3)
>  #define SYS_ICC_CTLR_EL1		sys_reg(3, 0, 12, 12, 4)
>  #define SYS_ICC_SRE_EL1			sys_reg(3, 0, 12, 12, 5)
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index d4f07f84602d..f0bc711db258 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -772,6 +772,26 @@ static void __hyp_text __vgic_v3_write_apxr3(struct kvm_vcpu *vcpu,
>  	__vgic_v3_write_apxrn(vcpu, rt, 3);
>  }
>  
> +static void __hyp_text __vgic_v3_read_hppir(struct kvm_vcpu *vcpu,
> +					    u32 vmcr, int rt)
> +{
> +	u64 lr_val;
> +	int lr, lr_grp, grp;
> +
> +	grp = __vgic_v3_get_group(vcpu);
> +
> +	lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
> +	if (lr == -1)
> +		goto spurious;
> +
> +	lr_grp = !!(lr_val & ICH_LR_GROUP);
> +	if (lr_grp != grp)
> +		lr_val = ICC_IAR1_EL1_SPURIOUS;

I don't get this.  The spec says that the special INTID 1023
  "...is returned in response to an interrupt acknowledge, if there is
   no pending interrupt with sufficient priority for it to be signaled to
   the PE, or if the highest priority pending interrupt is not
   appropriate for the:
    * Current Security state.  Interrupt group that is associated with
    * the System register."

So do we just take this to imply that it also covers the HPPIRx_EL1
registers (despite them being mentioned explicitly for the other special
INTIDs) or is there some other piece of spec I'm missing here?

Thanks,
-Christoffer

> +
> +spurious:
> +	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
> +}
> +
>  int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  {
>  	int rt;
> @@ -836,6 +856,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  		else
>  			fn = __vgic_v3_write_apxr3;
>  		break;
> +	case SYS_ICC_HPPIR1_EL1:
> +		fn = __vgic_v3_read_hppir;
> +		break;
>  	default:
>  		return 0;
>  	}
> -- 
> 2.11.0
> 

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

* [PATCH v2 10/25] KVM: arm64: vgic-v3: Add ICV_HPPIR1_EL1 handler
@ 2017-06-06 11:51     ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 11:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 01, 2017 at 11:21:02AM +0100, Marc Zyngier wrote:
> Add a handler for reading the guest's view of the ICV_HPPIR1_EL1
> register. This is a simple parsing of the available LRs, extracting the
> highest available interrupt.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  arch/arm64/include/asm/sysreg.h |  1 +
>  virt/kvm/arm/hyp/vgic-v3-sr.c   | 23 +++++++++++++++++++++++
>  2 files changed, 24 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index aad46b8eea5e..bd000686194a 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -185,6 +185,7 @@
>  #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
>  #define SYS_ICC_IAR1_EL1		sys_reg(3, 0, 12, 12, 0)
>  #define SYS_ICC_EOIR1_EL1		sys_reg(3, 0, 12, 12, 1)
> +#define SYS_ICC_HPPIR1_EL1		sys_reg(3, 0, 12, 12, 2)
>  #define SYS_ICC_BPR1_EL1		sys_reg(3, 0, 12, 12, 3)
>  #define SYS_ICC_CTLR_EL1		sys_reg(3, 0, 12, 12, 4)
>  #define SYS_ICC_SRE_EL1			sys_reg(3, 0, 12, 12, 5)
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index d4f07f84602d..f0bc711db258 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -772,6 +772,26 @@ static void __hyp_text __vgic_v3_write_apxr3(struct kvm_vcpu *vcpu,
>  	__vgic_v3_write_apxrn(vcpu, rt, 3);
>  }
>  
> +static void __hyp_text __vgic_v3_read_hppir(struct kvm_vcpu *vcpu,
> +					    u32 vmcr, int rt)
> +{
> +	u64 lr_val;
> +	int lr, lr_grp, grp;
> +
> +	grp = __vgic_v3_get_group(vcpu);
> +
> +	lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
> +	if (lr == -1)
> +		goto spurious;
> +
> +	lr_grp = !!(lr_val & ICH_LR_GROUP);
> +	if (lr_grp != grp)
> +		lr_val = ICC_IAR1_EL1_SPURIOUS;

I don't get this.  The spec says that the special INTID 1023
  "...is returned in response to an interrupt acknowledge, if there is
   no pending interrupt with sufficient priority for it to be signaled to
   the PE, or if the highest priority pending interrupt is not
   appropriate for the:
    * Current Security state.  Interrupt group that is associated with
    * the System register."

So do we just take this to imply that it also covers the HPPIRx_EL1
registers (despite them being mentioned explicitly for the other special
INTIDs) or is there some other piece of spec I'm missing here?

Thanks,
-Christoffer

> +
> +spurious:
> +	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
> +}
> +
>  int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  {
>  	int rt;
> @@ -836,6 +856,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  		else
>  			fn = __vgic_v3_write_apxr3;
>  		break;
> +	case SYS_ICC_HPPIR1_EL1:
> +		fn = __vgic_v3_read_hppir;
> +		break;
>  	default:
>  		return 0;
>  	}
> -- 
> 2.11.0
> 

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

* Re: [PATCH v2 12/25] KVM: arm64: Enable GICv3 Group-1 sysreg trapping via command-line
  2017-06-01 10:21   ` Marc Zyngier
@ 2017-06-06 12:06     ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 12:06 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On Thu, Jun 01, 2017 at 11:21:04AM +0100, Marc Zyngier wrote:
> Now that we're able to safely handle Group-1 sysreg access, let's
> give the user the opportunity to enable it by passing a specific
> command-line option (vgic_v3.group1_trap).
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  virt/kvm/arm/hyp/vgic-v3-sr.c |  6 +++++-
>  virt/kvm/arm/vgic/vgic-v3.c   | 11 +++++++++++
>  2 files changed, 16 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 8973bad35748..42ac9ee7650a 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -334,7 +334,11 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
>  		for (i = 0; i < used_lrs; i++)
>  			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
>  	} else {
> -		/* Always write ICH_HCR_EL2 to enable trapping */
> +		/*
> +                 * If we don't have any interrupt to inject, but that
> +		 * trapping is enabled, write the ICH_HCR_EL2 config
> +		 * anyway.
> +		 */

nit: Whitespace and grammar issues, and maybe this hunk was supposed to
be in the last patch?

>  		if (static_branch_unlikely(&vgic_v3_cpuif_trap))
>  			write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
>  	}
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index fbd678bc046d..a16769276efd 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -416,6 +416,12 @@ int vgic_v3_map_resources(struct kvm *kvm)
>  
>  DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap);
>  
> +static int __init early_group1_trap_cfg(char *buf)
> +{
> +	return strtobool(buf, &group1_trap);
> +}
> +early_param("vgic_v3.group1_trap", early_group1_trap_cfg);
> +

this shouldn't be named something with KVM (we're not going to trap
anything on the host somehow are we?)?

>  /**
>   * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
>   * @node:	pointer to the DT node
> @@ -467,6 +473,11 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
>  	if (kvm_vgic_global_state.vcpu_base == 0)
>  		kvm_info("disabling GICv2 emulation\n");
>  
> +	if (group1_trap) {
> +		kvm_info("GICv3 sysreg trapping enabled (reduced performance)\n");
> +		static_branch_enable(&vgic_v3_cpuif_trap);
> +	}
> +
>  	kvm_vgic_global_state.vctrl_base = NULL;
>  	kvm_vgic_global_state.type = VGIC_V3;
>  	kvm_vgic_global_state.max_gic_vcpus = VGIC_V3_MAX_CPUS;
> -- 
> 2.11.0
> 

Thanks,
-Christoffer

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

* [PATCH v2 12/25] KVM: arm64: Enable GICv3 Group-1 sysreg trapping via command-line
@ 2017-06-06 12:06     ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 12:06 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 01, 2017 at 11:21:04AM +0100, Marc Zyngier wrote:
> Now that we're able to safely handle Group-1 sysreg access, let's
> give the user the opportunity to enable it by passing a specific
> command-line option (vgic_v3.group1_trap).
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  virt/kvm/arm/hyp/vgic-v3-sr.c |  6 +++++-
>  virt/kvm/arm/vgic/vgic-v3.c   | 11 +++++++++++
>  2 files changed, 16 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 8973bad35748..42ac9ee7650a 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -334,7 +334,11 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
>  		for (i = 0; i < used_lrs; i++)
>  			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
>  	} else {
> -		/* Always write ICH_HCR_EL2 to enable trapping */
> +		/*
> +                 * If we don't have any interrupt to inject, but that
> +		 * trapping is enabled, write the ICH_HCR_EL2 config
> +		 * anyway.
> +		 */

nit: Whitespace and grammar issues, and maybe this hunk was supposed to
be in the last patch?

>  		if (static_branch_unlikely(&vgic_v3_cpuif_trap))
>  			write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
>  	}
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index fbd678bc046d..a16769276efd 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -416,6 +416,12 @@ int vgic_v3_map_resources(struct kvm *kvm)
>  
>  DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap);
>  
> +static int __init early_group1_trap_cfg(char *buf)
> +{
> +	return strtobool(buf, &group1_trap);
> +}
> +early_param("vgic_v3.group1_trap", early_group1_trap_cfg);
> +

this shouldn't be named something with KVM (we're not going to trap
anything on the host somehow are we?)?

>  /**
>   * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
>   * @node:	pointer to the DT node
> @@ -467,6 +473,11 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
>  	if (kvm_vgic_global_state.vcpu_base == 0)
>  		kvm_info("disabling GICv2 emulation\n");
>  
> +	if (group1_trap) {
> +		kvm_info("GICv3 sysreg trapping enabled (reduced performance)\n");
> +		static_branch_enable(&vgic_v3_cpuif_trap);
> +	}
> +
>  	kvm_vgic_global_state.vctrl_base = NULL;
>  	kvm_vgic_global_state.type = VGIC_V3;
>  	kvm_vgic_global_state.max_gic_vcpus = VGIC_V3_MAX_CPUS;
> -- 
> 2.11.0
> 

Thanks,
-Christoffer

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

* Re: [PATCH v2 13/25] KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler
  2017-06-01 10:21   ` Marc Zyngier
@ 2017-06-06 12:11     ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 12:11 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On Thu, Jun 01, 2017 at 11:21:05AM +0100, Marc Zyngier wrote:
> Add a handler for reading/writing the guest's view of the ICC_BPR0_EL1
> register, which is located in the ICH_VMCR_EL2.BPR0 field.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  arch/arm64/include/asm/sysreg.h |  1 +
>  virt/kvm/arm/hyp/vgic-v3-sr.c   | 36 ++++++++++++++++++++++++++++++++++++
>  2 files changed, 37 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index bd000686194a..d20be0b28ca4 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -180,6 +180,7 @@
>  
>  #define SYS_VBAR_EL1			sys_reg(3, 0, 12, 0, 0)
>  
> +#define SYS_ICC_BPR0_EL1		sys_reg(3, 0, 12, 8, 3)
>  #define SYS_ICC_AP1Rn_EL1(n)		sys_reg(3, 0, 12, 9, n)
>  #define SYS_ICC_DIR_EL1			sys_reg(3, 0, 12, 11, 1)
>  #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 42ac9ee7650a..54a8e828c85b 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -688,11 +688,41 @@ static void __hyp_text __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr,
>  	__vgic_v3_write_vmcr(vmcr);
>  }
>  
> +static void __hyp_text __vgic_v3_read_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> +{
> +	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr0(vmcr));
> +}
> +
>  static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  {
>  	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
>  }
>  
> +static void __hyp_text __vgic_v3_write_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> +{
> +	u64 val = vcpu_get_reg(vcpu, rt);
> +	u8 bpr_min = 7 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> +
> +	/* Enforce BPR limiting */
> +	if (val < bpr_min)
> +		val = bpr_min;
> +
> +	val <<= ICH_VMCR_BPR0_SHIFT;
> +	val &= ICH_VMCR_BPR0_MASK;
> +	vmcr &= ~ICH_VMCR_BPR0_MASK;
> +	vmcr |= val;
> +
> +	if (vmcr & ICH_VMCR_CBPR_MASK) {
> +		val = __vgic_v3_get_bpr1(vmcr);
> +		val <<= ICH_VMCR_BPR1_SHIFT;
> +		val &= ICH_VMCR_BPR1_MASK;
> +		vmcr &= ~ICH_VMCR_BPR1_MASK;
> +		vmcr |= val;
> +	}

I don't understand why this block is needed?

Thanks,
-Christoffer

> +
> +	__vgic_v3_write_vmcr(vmcr);
> +}
> +
>  static void __hyp_text __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  {
>  	u64 val = vcpu_get_reg(vcpu, rt);
> @@ -870,6 +900,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  	case SYS_ICC_HPPIR1_EL1:
>  		fn = __vgic_v3_read_hppir;
>  		break;
> +	case SYS_ICC_BPR0_EL1:
> +		if (is_read)
> +			fn = __vgic_v3_read_bpr0;
> +		else
> +			fn = __vgic_v3_write_bpr0;
> +		break;
>  	default:
>  		return 0;
>  	}
> -- 
> 2.11.0
> 

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

* [PATCH v2 13/25] KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler
@ 2017-06-06 12:11     ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 12:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 01, 2017 at 11:21:05AM +0100, Marc Zyngier wrote:
> Add a handler for reading/writing the guest's view of the ICC_BPR0_EL1
> register, which is located in the ICH_VMCR_EL2.BPR0 field.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  arch/arm64/include/asm/sysreg.h |  1 +
>  virt/kvm/arm/hyp/vgic-v3-sr.c   | 36 ++++++++++++++++++++++++++++++++++++
>  2 files changed, 37 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index bd000686194a..d20be0b28ca4 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -180,6 +180,7 @@
>  
>  #define SYS_VBAR_EL1			sys_reg(3, 0, 12, 0, 0)
>  
> +#define SYS_ICC_BPR0_EL1		sys_reg(3, 0, 12, 8, 3)
>  #define SYS_ICC_AP1Rn_EL1(n)		sys_reg(3, 0, 12, 9, n)
>  #define SYS_ICC_DIR_EL1			sys_reg(3, 0, 12, 11, 1)
>  #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 42ac9ee7650a..54a8e828c85b 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -688,11 +688,41 @@ static void __hyp_text __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr,
>  	__vgic_v3_write_vmcr(vmcr);
>  }
>  
> +static void __hyp_text __vgic_v3_read_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> +{
> +	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr0(vmcr));
> +}
> +
>  static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  {
>  	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
>  }
>  
> +static void __hyp_text __vgic_v3_write_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> +{
> +	u64 val = vcpu_get_reg(vcpu, rt);
> +	u8 bpr_min = 7 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> +
> +	/* Enforce BPR limiting */
> +	if (val < bpr_min)
> +		val = bpr_min;
> +
> +	val <<= ICH_VMCR_BPR0_SHIFT;
> +	val &= ICH_VMCR_BPR0_MASK;
> +	vmcr &= ~ICH_VMCR_BPR0_MASK;
> +	vmcr |= val;
> +
> +	if (vmcr & ICH_VMCR_CBPR_MASK) {
> +		val = __vgic_v3_get_bpr1(vmcr);
> +		val <<= ICH_VMCR_BPR1_SHIFT;
> +		val &= ICH_VMCR_BPR1_MASK;
> +		vmcr &= ~ICH_VMCR_BPR1_MASK;
> +		vmcr |= val;
> +	}

I don't understand why this block is needed?

Thanks,
-Christoffer

> +
> +	__vgic_v3_write_vmcr(vmcr);
> +}
> +
>  static void __hyp_text __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  {
>  	u64 val = vcpu_get_reg(vcpu, rt);
> @@ -870,6 +900,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  	case SYS_ICC_HPPIR1_EL1:
>  		fn = __vgic_v3_read_hppir;
>  		break;
> +	case SYS_ICC_BPR0_EL1:
> +		if (is_read)
> +			fn = __vgic_v3_read_bpr0;
> +		else
> +			fn = __vgic_v3_write_bpr0;
> +		break;
>  	default:
>  		return 0;
>  	}
> -- 
> 2.11.0
> 

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

* Re: [PATCH v2 17/25] KVM: arm64: Enable GICv3 Group-0 sysreg trapping via command-line
  2017-06-01 10:21   ` Marc Zyngier
@ 2017-06-06 12:44     ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 12:44 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On Thu, Jun 01, 2017 at 11:21:09AM +0100, Marc Zyngier wrote:
> Now that we're able to safely handle Group-0 sysreg access, let's
> give the user the opportunity to enable it by passing a specific
> command-line option (vgic_v3.group0_trap).
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic-v3.c | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 7525216ef988..1486ce25edcb 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -419,6 +419,12 @@ int vgic_v3_map_resources(struct kvm *kvm)
>  
>  DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap);
>  
> +static int __init early_group0_trap_cfg(char *buf)
> +{
> +	return strtobool(buf, &group0_trap);
> +}
> +early_param("vgic_v3.group0_trap", early_group0_trap_cfg);
> +

same comment as before, if this should be called something with KVM.

Also, btw., what's the policy on adding new kernel parameters?  Should
they be documented in kernel-parameters.txt or is that auto-generated
these days?

Thanks,
-Christoffer

>  static int __init early_group1_trap_cfg(char *buf)
>  {
>  	return strtobool(buf, &group1_trap);
> -- 
> 2.11.0
> 

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

* [PATCH v2 17/25] KVM: arm64: Enable GICv3 Group-0 sysreg trapping via command-line
@ 2017-06-06 12:44     ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 12:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 01, 2017 at 11:21:09AM +0100, Marc Zyngier wrote:
> Now that we're able to safely handle Group-0 sysreg access, let's
> give the user the opportunity to enable it by passing a specific
> command-line option (vgic_v3.group0_trap).
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic-v3.c | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 7525216ef988..1486ce25edcb 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -419,6 +419,12 @@ int vgic_v3_map_resources(struct kvm *kvm)
>  
>  DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap);
>  
> +static int __init early_group0_trap_cfg(char *buf)
> +{
> +	return strtobool(buf, &group0_trap);
> +}
> +early_param("vgic_v3.group0_trap", early_group0_trap_cfg);
> +

same comment as before, if this should be called something with KVM.

Also, btw., what's the policy on adding new kernel parameters?  Should
they be documented in kernel-parameters.txt or is that auto-generated
these days?

Thanks,
-Christoffer

>  static int __init early_group1_trap_cfg(char *buf)
>  {
>  	return strtobool(buf, &group1_trap);
> -- 
> 2.11.0
> 

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

* Re: [PATCH v2 19/25] arm64: Add workaround for Cavium Thunder erratum 30115
  2017-06-01 10:21   ` Marc Zyngier
@ 2017-06-06 12:48     ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 12:48 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On Thu, Jun 01, 2017 at 11:21:11AM +0100, Marc Zyngier wrote:
> From: David Daney <david.daney@cavium.com>
> 
> Some Cavium Thunder CPUs suffer a problem where a KVM guest may
> inadvertently cause the host kernel to quit receiving interrupts.
> 
> Use the Group-0/1 trapping in order to deal with it.
> 
> [maz]: Adapted patch to the Group-0/1 trapping, reworked commit log
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: David Daney <david.daney@cavium.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  Documentation/arm64/silicon-errata.txt |  1 +
>  arch/arm64/Kconfig                     | 11 +++++++++++
>  arch/arm64/include/asm/cpucaps.h       |  3 ++-
>  arch/arm64/kernel/cpu_errata.c         | 21 +++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v3.c            |  7 +++++++
>  5 files changed, 42 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt
> index 10f2dddbf449..f5f93dca54b7 100644
> --- a/Documentation/arm64/silicon-errata.txt
> +++ b/Documentation/arm64/silicon-errata.txt
> @@ -62,6 +62,7 @@ stable kernels.
>  | Cavium         | ThunderX GICv3  | #23154          | CAVIUM_ERRATUM_23154        |
>  | Cavium         | ThunderX Core   | #27456          | CAVIUM_ERRATUM_27456        |
>  | Cavium         | ThunderX SMMUv2 | #27704          | N/A                         |
> +| Cavium         | ThunderX Core   | #30115          | CAVIUM_ERRATUM_30115        |
>  |                |                 |                 |                             |
>  | Freescale/NXP  | LS2080A/LS1043A | A-008585        | FSL_ERRATUM_A008585         |
>  |                |                 |                 |                             |
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 3dcd7ec69bca..0950b21e4d17 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -480,6 +480,17 @@ config CAVIUM_ERRATUM_27456
>  
>  	  If unsure, say Y.
>  
> +config CAVIUM_ERRATUM_30115
> +	bool "Cavium erratum 30115: Guest may disable interrupts in host"
> +	default y
> +	help
> +	  On ThunderX T88 pass 1.x through 2.2, T81 pass 1.0 through
> +	  1.2, and T83 Pass 1.0, KVM guest execution may disable
> +	  interrupts in host. Trapping GICv3 group-1 accesses sidesteps
> +	  the issue.
> +
> +	  If unsure, say Y.
> +
>  config QCOM_FALKOR_ERRATUM_1003
>  	bool "Falkor E1003: Incorrect translation due to ASID change"
>  	default y
> diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
> index b3aab8a17868..8d2272c6822c 100644
> --- a/arch/arm64/include/asm/cpucaps.h
> +++ b/arch/arm64/include/asm/cpucaps.h
> @@ -38,7 +38,8 @@
>  #define ARM64_WORKAROUND_REPEAT_TLBI		17
>  #define ARM64_WORKAROUND_QCOM_FALKOR_E1003	18
>  #define ARM64_WORKAROUND_858921			19
> +#define ARM64_WORKAROUND_CAVIUM_30115		20
>  
> -#define ARM64_NCAPS				20
> +#define ARM64_NCAPS				21
>  
>  #endif /* __ASM_CPUCAPS_H */
> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
> index 2ed2a7657711..0e27f86ee709 100644
> --- a/arch/arm64/kernel/cpu_errata.c
> +++ b/arch/arm64/kernel/cpu_errata.c
> @@ -133,6 +133,27 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
>  		MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x00),
>  	},
>  #endif
> +#ifdef CONFIG_CAVIUM_ERRATUM_30115
> +	{
> +	/* Cavium ThunderX, T88 pass 1.x - 2.2 */
> +		.desc = "Cavium erratum 30115",
> +		.capability = ARM64_WORKAROUND_CAVIUM_30115,
> +		MIDR_RANGE(MIDR_THUNDERX, 0x00,
> +			   (1 << MIDR_VARIANT_SHIFT) | 2),
> +	},
> +	{
> +	/* Cavium ThunderX, T81 pass 1.0 - 1.2 */
> +		.desc = "Cavium erratum 30115",
> +		.capability = ARM64_WORKAROUND_CAVIUM_30115,
> +		MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x02),
> +	},
> +	{
> +	/* Cavium ThunderX, T83 pass 1.0 */
> +		.desc = "Cavium erratum 30115",
> +		.capability = ARM64_WORKAROUND_CAVIUM_30115,
> +		MIDR_RANGE(MIDR_THUNDERX_83XX, 0x00, 0x00),
> +	},
> +#endif
>  	{
>  		.desc = "Mismatched cache line size",
>  		.capability = ARM64_MISMATCHED_CACHE_LINE_SIZE,
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 1486ce25edcb..062be1fe95b5 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -482,6 +482,13 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
>  	if (kvm_vgic_global_state.vcpu_base == 0)
>  		kvm_info("disabling GICv2 emulation\n");
>  
> +#ifdef CONFIG_ARM64
> +	if (cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_30115)) {
> +		group0_trap = true;
> +		group1_trap = true;

Why does the config help text say that trapping group 1 accesses is
enough, yet we trap both group 0 and group 1 ?

> +	}
> +#endif
> +
>  	if (group0_trap || group1_trap) {
>  		kvm_info("GICv3 sysreg trapping enabled (reduced performance)\n");
>  		static_branch_enable(&vgic_v3_cpuif_trap);
> -- 
> 2.11.0
> 

Thanks,
-Christoffer

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

* [PATCH v2 19/25] arm64: Add workaround for Cavium Thunder erratum 30115
@ 2017-06-06 12:48     ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 12:48 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 01, 2017 at 11:21:11AM +0100, Marc Zyngier wrote:
> From: David Daney <david.daney@cavium.com>
> 
> Some Cavium Thunder CPUs suffer a problem where a KVM guest may
> inadvertently cause the host kernel to quit receiving interrupts.
> 
> Use the Group-0/1 trapping in order to deal with it.
> 
> [maz]: Adapted patch to the Group-0/1 trapping, reworked commit log
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: David Daney <david.daney@cavium.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  Documentation/arm64/silicon-errata.txt |  1 +
>  arch/arm64/Kconfig                     | 11 +++++++++++
>  arch/arm64/include/asm/cpucaps.h       |  3 ++-
>  arch/arm64/kernel/cpu_errata.c         | 21 +++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v3.c            |  7 +++++++
>  5 files changed, 42 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt
> index 10f2dddbf449..f5f93dca54b7 100644
> --- a/Documentation/arm64/silicon-errata.txt
> +++ b/Documentation/arm64/silicon-errata.txt
> @@ -62,6 +62,7 @@ stable kernels.
>  | Cavium         | ThunderX GICv3  | #23154          | CAVIUM_ERRATUM_23154        |
>  | Cavium         | ThunderX Core   | #27456          | CAVIUM_ERRATUM_27456        |
>  | Cavium         | ThunderX SMMUv2 | #27704          | N/A                         |
> +| Cavium         | ThunderX Core   | #30115          | CAVIUM_ERRATUM_30115        |
>  |                |                 |                 |                             |
>  | Freescale/NXP  | LS2080A/LS1043A | A-008585        | FSL_ERRATUM_A008585         |
>  |                |                 |                 |                             |
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 3dcd7ec69bca..0950b21e4d17 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -480,6 +480,17 @@ config CAVIUM_ERRATUM_27456
>  
>  	  If unsure, say Y.
>  
> +config CAVIUM_ERRATUM_30115
> +	bool "Cavium erratum 30115: Guest may disable interrupts in host"
> +	default y
> +	help
> +	  On ThunderX T88 pass 1.x through 2.2, T81 pass 1.0 through
> +	  1.2, and T83 Pass 1.0, KVM guest execution may disable
> +	  interrupts in host. Trapping GICv3 group-1 accesses sidesteps
> +	  the issue.
> +
> +	  If unsure, say Y.
> +
>  config QCOM_FALKOR_ERRATUM_1003
>  	bool "Falkor E1003: Incorrect translation due to ASID change"
>  	default y
> diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
> index b3aab8a17868..8d2272c6822c 100644
> --- a/arch/arm64/include/asm/cpucaps.h
> +++ b/arch/arm64/include/asm/cpucaps.h
> @@ -38,7 +38,8 @@
>  #define ARM64_WORKAROUND_REPEAT_TLBI		17
>  #define ARM64_WORKAROUND_QCOM_FALKOR_E1003	18
>  #define ARM64_WORKAROUND_858921			19
> +#define ARM64_WORKAROUND_CAVIUM_30115		20
>  
> -#define ARM64_NCAPS				20
> +#define ARM64_NCAPS				21
>  
>  #endif /* __ASM_CPUCAPS_H */
> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
> index 2ed2a7657711..0e27f86ee709 100644
> --- a/arch/arm64/kernel/cpu_errata.c
> +++ b/arch/arm64/kernel/cpu_errata.c
> @@ -133,6 +133,27 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
>  		MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x00),
>  	},
>  #endif
> +#ifdef CONFIG_CAVIUM_ERRATUM_30115
> +	{
> +	/* Cavium ThunderX, T88 pass 1.x - 2.2 */
> +		.desc = "Cavium erratum 30115",
> +		.capability = ARM64_WORKAROUND_CAVIUM_30115,
> +		MIDR_RANGE(MIDR_THUNDERX, 0x00,
> +			   (1 << MIDR_VARIANT_SHIFT) | 2),
> +	},
> +	{
> +	/* Cavium ThunderX, T81 pass 1.0 - 1.2 */
> +		.desc = "Cavium erratum 30115",
> +		.capability = ARM64_WORKAROUND_CAVIUM_30115,
> +		MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x02),
> +	},
> +	{
> +	/* Cavium ThunderX, T83 pass 1.0 */
> +		.desc = "Cavium erratum 30115",
> +		.capability = ARM64_WORKAROUND_CAVIUM_30115,
> +		MIDR_RANGE(MIDR_THUNDERX_83XX, 0x00, 0x00),
> +	},
> +#endif
>  	{
>  		.desc = "Mismatched cache line size",
>  		.capability = ARM64_MISMATCHED_CACHE_LINE_SIZE,
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 1486ce25edcb..062be1fe95b5 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -482,6 +482,13 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
>  	if (kvm_vgic_global_state.vcpu_base == 0)
>  		kvm_info("disabling GICv2 emulation\n");
>  
> +#ifdef CONFIG_ARM64
> +	if (cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_30115)) {
> +		group0_trap = true;
> +		group1_trap = true;

Why does the config help text say that trapping group 1 accesses is
enough, yet we trap both group 0 and group 1 ?

> +	}
> +#endif
> +
>  	if (group0_trap || group1_trap) {
>  		kvm_info("GICv3 sysreg trapping enabled (reduced performance)\n");
>  		static_branch_enable(&vgic_v3_cpuif_trap);
> -- 
> 2.11.0
> 

Thanks,
-Christoffer

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

* Re: [PATCH v2 20/25] KVM: arm64: vgic-v3: Add ICV_DIR_EL1 handler
  2017-06-01 10:21   ` Marc Zyngier
@ 2017-06-06 12:59     ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 12:59 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter,
	linux-arm-kernel, kvmarm

On Thu, Jun 01, 2017 at 11:21:12AM +0100, Marc Zyngier wrote:
> Add a handler for writing the guest's view of the ICC_DIR_EL1
> register, performing the deactivation of an interrupt if EOImode
> is set ot 1.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Reviewed-by: Christoffer Dall <cdall@linaro.org>

> ---
>  virt/kvm/arm/hyp/vgic-v3-sr.c | 27 +++++++++++++++++++++++++++
>  1 file changed, 27 insertions(+)
> 
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 5ff788d308ee..b86a0776c407 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -634,6 +634,30 @@ static void __hyp_text __vgic_v3_bump_eoicount(void)
>  	write_gicreg(hcr, ICH_HCR_EL2);
>  }
>  
> +static void __hyp_text __vgic_v3_write_dir(struct kvm_vcpu *vcpu,
> +					   u32 vmcr, int rt)
> +{
> +	u32 vid = vcpu_get_reg(vcpu, rt);
> +	u64 lr_val;
> +	int lr;
> +
> +	/* EOImode == 0, nothing to be done here */
> +	if (!(vmcr & ICH_VMCR_EOIM_MASK))
> +		return;
> +
> +	/* No deactivate to be performed on an LPI */
> +	if (vid >= VGIC_MIN_LPI)
> +		return;
> +
> +	lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val);
> +	if (lr == -1) {
> +		__vgic_v3_bump_eoicount();
> +		return;
> +	}
> +
> +	__vgic_v3_clear_active_lr(lr, lr_val);
> +}
> +
>  static void __hyp_text __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  {
>  	u32 vid = vcpu_get_reg(vcpu, rt);
> @@ -936,6 +960,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  		else
>  			fn = __vgic_v3_write_bpr0;
>  		break;
> +	case SYS_ICC_DIR_EL1:
> +		fn = __vgic_v3_write_dir;
> +		break;
>  	default:
>  		return 0;
>  	}
> -- 
> 2.11.0
> 

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

* [PATCH v2 20/25] KVM: arm64: vgic-v3: Add ICV_DIR_EL1 handler
@ 2017-06-06 12:59     ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 12:59 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 01, 2017 at 11:21:12AM +0100, Marc Zyngier wrote:
> Add a handler for writing the guest's view of the ICC_DIR_EL1
> register, performing the deactivation of an interrupt if EOImode
> is set ot 1.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Reviewed-by: Christoffer Dall <cdall@linaro.org>

> ---
>  virt/kvm/arm/hyp/vgic-v3-sr.c | 27 +++++++++++++++++++++++++++
>  1 file changed, 27 insertions(+)
> 
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 5ff788d308ee..b86a0776c407 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -634,6 +634,30 @@ static void __hyp_text __vgic_v3_bump_eoicount(void)
>  	write_gicreg(hcr, ICH_HCR_EL2);
>  }
>  
> +static void __hyp_text __vgic_v3_write_dir(struct kvm_vcpu *vcpu,
> +					   u32 vmcr, int rt)
> +{
> +	u32 vid = vcpu_get_reg(vcpu, rt);
> +	u64 lr_val;
> +	int lr;
> +
> +	/* EOImode == 0, nothing to be done here */
> +	if (!(vmcr & ICH_VMCR_EOIM_MASK))
> +		return;
> +
> +	/* No deactivate to be performed on an LPI */
> +	if (vid >= VGIC_MIN_LPI)
> +		return;
> +
> +	lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val);
> +	if (lr == -1) {
> +		__vgic_v3_bump_eoicount();
> +		return;
> +	}
> +
> +	__vgic_v3_clear_active_lr(lr, lr_val);
> +}
> +
>  static void __hyp_text __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  {
>  	u32 vid = vcpu_get_reg(vcpu, rt);
> @@ -936,6 +960,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  		else
>  			fn = __vgic_v3_write_bpr0;
>  		break;
> +	case SYS_ICC_DIR_EL1:
> +		fn = __vgic_v3_write_dir;
> +		break;
>  	default:
>  		return 0;
>  	}
> -- 
> 2.11.0
> 

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

* Re: [PATCH v2 08/25] KVM: arm64: vgic-v3: Add ICV_EOIR1_EL1 handler
  2017-06-05 11:00       ` Marc Zyngier
@ 2017-06-06 13:19         ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:19 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On Mon, Jun 05, 2017 at 12:00:08PM +0100, Marc Zyngier wrote:
> On 05/06/17 11:32, Christoffer Dall wrote:
> > On Thu, Jun 01, 2017 at 11:21:00AM +0100, Marc Zyngier wrote:
> >> Add a handler for writing the guest's view of the ICC_EOIR1_EL1
> >> register. This involves dropping the priority of the interrupt,
> >> and deactivating it if required (EOImode == 0).
> >>
> >> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> ---
> >>  include/linux/irqchip/arm-gic-v3.h |   2 +
> >>  virt/kvm/arm/hyp/vgic-v3-sr.c      | 121 +++++++++++++++++++++++++++++++++++++
> >>  2 files changed, 123 insertions(+)
> >>
> >> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> >> index 401db585a534..e50ce5d416a3 100644
> >> --- a/include/linux/irqchip/arm-gic-v3.h
> >> +++ b/include/linux/irqchip/arm-gic-v3.h
> >> @@ -417,6 +417,8 @@
> >>  
> >>  #define ICH_HCR_EN			(1 << 0)
> >>  #define ICH_HCR_UIE			(1 << 1)
> >> +#define ICH_HCR_EOIcount_SHIFT		27
> >> +#define ICH_HCR_EOIcount_MASK		(0x1f << ICH_HCR_EOIcount_SHIFT)
> >>  
> >>  #define ICH_VMCR_CBPR_SHIFT		4
> >>  #define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
> >> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> index 16a2eadc7a5c..3f04122a5d4d 100644
> >> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> @@ -426,6 +426,26 @@ static int __hyp_text __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu,
> >>  	return lr;
> >>  }
> >>  
> >> +static int __hyp_text __vgic_v3_find_active_lr(struct kvm_vcpu *vcpu,
> >> +					       int intid, u64 *lr_val)
> >> +{
> >> +	unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
> >> +	int i;
> >> +
> >> +	for (i = 0; i < used_lrs; i++) {
> >> +		u64 val = __gic_v3_get_lr(i);
> >> +
> >> +		if ((val & ICH_LR_VIRTUAL_ID_MASK) == intid &&
> >> +		    (val & ICH_LR_ACTIVE_BIT)) {
> >> +			*lr_val = val;
> >> +			return i;
> >> +		}
> >> +	}
> >> +
> >> +	*lr_val = ICC_IAR1_EL1_SPURIOUS;
> >> +	return -1;
> >> +}
> >> +
> >>  static int __hyp_text __vgic_v3_get_highest_active_priority(void)
> >>  {
> >>  	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> >> @@ -506,6 +526,45 @@ static void __hyp_text __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp)
> >>  	__vgic_v3_write_ap1rn(val | BIT(ap % 32), apr);
> >>  }
> >>  
> >> +static int __hyp_text __vgic_v3_clear_highest_active_priority(void)
> >> +{
> >> +	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> >> +	u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
> >> +	u32 hap = 0;
> >> +	int i;
> >> +
> >> +	for (i = 0; i < nr_apr_regs; i++) {
> >> +		u32 ap0, ap1;
> >> +		int c0, c1;
> >> +
> >> +		ap0 = __vgic_v3_read_ap0rn(i);
> >> +		ap1 = __vgic_v3_read_ap1rn(i);
> > 
> > so reading a group 1 interrupt from the IAR and writing that value back
> > to the EOIR1_EL1 register can somehow clear the priority of a group 0
> > interrupt?
> 
> If you properly nest the IAR and EOI, nothing bad will happen (group
> priorities are not supposed to overlap). If you decide to do weird
> things, you'll be in UNPREDICTABLE territory, and some interrupts can be
> left active while you deactivate the wrong one.
> 
> > Or did you just want a generic function that does what it's supposed to
> > regardless of which register was written to etc.?
> 
> That's the goal indeed.
> 
> > 
> >> +		if (!ap0 && !ap1) {
> >> +			hap += 32;
> >> +			continue;
> >> +		}
> >> +
> >> +		c0 = ap0 ? __ffs(ap0) : 32;
> >> +		c1 = ap1 ? __ffs(ap1) : 32;
> >> +
> >> +		/* Always clear the LSB, which is the highest priority */
> >> +		if (c0 < c1) {
> >> +			ap0 &= ~BIT(c0);
> >> +			__vgic_v3_write_ap0rn(ap0, i);
> >> +			hap += c0;
> >> +		} else {
> >> +			ap1 &= ~BIT(c1);
> >> +			__vgic_v3_write_ap1rn(ap1, i);
> >> +			hap += c1;
> > 
> > Can we ever have a situation where c0 == c1?  And in that case, should
> > you prioritize clearing the group 1 apr ?
> 
> You shouldn't ever have this case. The spec says:
> 
> "Having the bit corresponding to a priority set to 1 in both
> ICH_AP0R<n>_EL2 and ICH_AP1R<n>_EL2 might result in UNPREDICTABLE
> behavior of the interrupt prioritization system for virtual interrupts."
> 

ok, so the guest is just doing weird things, and because we're just
mediating the access to the hardware that the guest would normally have
at EL1, even though we're doing stuff from EL2, the hardware should
still be sane enough to never hurt the host.

> >> +		}
> >> +
> >> +		/* Rescale to 8 bits of priority */
> >> +		return hap << (8 - nr_pre_bits);
> >> +	}
> >> +
> >> +	return GICv3_IDLE_PRIORITY;
> >> +}
> >> +
> >>  static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >>  {
> >>  	u64 lr_val;
> >> @@ -542,6 +601,65 @@ static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int r
> >>  	vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS);
> >>  }
> >>  
> >> +static void __hyp_text __vgic_v3_clear_active_lr(int lr, u64 lr_val)
> >> +{
> >> +	lr_val &= ~ICH_LR_ACTIVE_BIT;
> >> +	if (lr_val & ICH_LR_HW) {
> >> +		u32 pid;
> >> +
> >> +		pid = (lr_val & ICH_LR_PHYS_ID_MASK) >> ICH_LR_PHYS_ID_SHIFT;
> >> +		gic_write_dir(pid);
> > 
> > Yikes, scary.  I can't think of this breaking anything.  But, scary.
> 
> I know. a (slightly) less scary approach would be to go all the way back
> to EL1 and to the DIR write there, but I don't thing this buys us
> anything but wasted cycles...
> 

No, it should end up being the same, so no reason to bother.

> > 
> >> +	}
> >> +
> >> +	__gic_v3_set_lr(lr_val, lr);
> >> +}
> >> +
> >> +static void __hyp_text __vgic_v3_bump_eoicount(void)
> >> +{
> >> +	u32 hcr;
> >> +
> >> +	hcr = read_gicreg(ICH_HCR_EL2);
> >> +	hcr += 1 << ICH_HCR_EOIcount_SHIFT;
> >> +	write_gicreg(hcr, ICH_HCR_EL2);
> >> +}
> >> +
> >> +static void __hyp_text __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >> +{
> >> +	u32 vid = vcpu_get_reg(vcpu, rt);
> >> +	u64 lr_val;
> >> +	u8 lr_prio, act_prio;
> >> +	int lr, grp;
> >> +
> >> +	grp = __vgic_v3_get_group(vcpu);
> >> +
> >> +	/* Drop priority in any case */
> >> +	act_prio = __vgic_v3_clear_highest_active_priority();
> >> +
> >> +	/* If EOIing an LPI, no deactivate to be performed */
> >> +	if (vid >= VGIC_MIN_LPI)
> >> +		return;
> >> +
> >> +	/* EOImode == 1, nothing to be done here */
> >> +	if (vmcr & ICH_VMCR_EOIM_MASK)
> >> +		return;
> >> +
> >> +	lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val);
> >> +	if (lr == -1) {
> >> +		__vgic_v3_bump_eoicount();
> >> +		return;
> >> +	}
> >> +
> >> +	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
> >> +
> >> +	/* If priorities or group do not match, the guest has fscked-up. */
> >> +	if (grp != !!(lr_val & ICH_LR_GROUP) ||
> >> +	    __vgic_v3_pri_to_pre(lr_prio, vmcr, grp) != act_prio)
> >> +		return;
> > 
> > Since we've cleared the highest priority above, is there any way for the
> > guest to recover from this, or do this particular (v)GIC implementation
> > have the implementation defined behavior of a write with something else
> > than the last valid read from the IAR of the same group to the EOIR
> > means that the system is toast?
> 
> The only way to recover from such a situation from a guest PoV is to
> write its APRs to zero, turn everything off, reset the whole GIC, and
> restart from scratch. Not pleasant...
> 
ok, fair enough, the guest asked for it, we give it.

Thanks,
-Christoffer

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

* [PATCH v2 08/25] KVM: arm64: vgic-v3: Add ICV_EOIR1_EL1 handler
@ 2017-06-06 13:19         ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:19 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jun 05, 2017 at 12:00:08PM +0100, Marc Zyngier wrote:
> On 05/06/17 11:32, Christoffer Dall wrote:
> > On Thu, Jun 01, 2017 at 11:21:00AM +0100, Marc Zyngier wrote:
> >> Add a handler for writing the guest's view of the ICC_EOIR1_EL1
> >> register. This involves dropping the priority of the interrupt,
> >> and deactivating it if required (EOImode == 0).
> >>
> >> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> ---
> >>  include/linux/irqchip/arm-gic-v3.h |   2 +
> >>  virt/kvm/arm/hyp/vgic-v3-sr.c      | 121 +++++++++++++++++++++++++++++++++++++
> >>  2 files changed, 123 insertions(+)
> >>
> >> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> >> index 401db585a534..e50ce5d416a3 100644
> >> --- a/include/linux/irqchip/arm-gic-v3.h
> >> +++ b/include/linux/irqchip/arm-gic-v3.h
> >> @@ -417,6 +417,8 @@
> >>  
> >>  #define ICH_HCR_EN			(1 << 0)
> >>  #define ICH_HCR_UIE			(1 << 1)
> >> +#define ICH_HCR_EOIcount_SHIFT		27
> >> +#define ICH_HCR_EOIcount_MASK		(0x1f << ICH_HCR_EOIcount_SHIFT)
> >>  
> >>  #define ICH_VMCR_CBPR_SHIFT		4
> >>  #define ICH_VMCR_CBPR_MASK		(1 << ICH_VMCR_CBPR_SHIFT)
> >> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> index 16a2eadc7a5c..3f04122a5d4d 100644
> >> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> @@ -426,6 +426,26 @@ static int __hyp_text __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu,
> >>  	return lr;
> >>  }
> >>  
> >> +static int __hyp_text __vgic_v3_find_active_lr(struct kvm_vcpu *vcpu,
> >> +					       int intid, u64 *lr_val)
> >> +{
> >> +	unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
> >> +	int i;
> >> +
> >> +	for (i = 0; i < used_lrs; i++) {
> >> +		u64 val = __gic_v3_get_lr(i);
> >> +
> >> +		if ((val & ICH_LR_VIRTUAL_ID_MASK) == intid &&
> >> +		    (val & ICH_LR_ACTIVE_BIT)) {
> >> +			*lr_val = val;
> >> +			return i;
> >> +		}
> >> +	}
> >> +
> >> +	*lr_val = ICC_IAR1_EL1_SPURIOUS;
> >> +	return -1;
> >> +}
> >> +
> >>  static int __hyp_text __vgic_v3_get_highest_active_priority(void)
> >>  {
> >>  	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> >> @@ -506,6 +526,45 @@ static void __hyp_text __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp)
> >>  	__vgic_v3_write_ap1rn(val | BIT(ap % 32), apr);
> >>  }
> >>  
> >> +static int __hyp_text __vgic_v3_clear_highest_active_priority(void)
> >> +{
> >> +	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> >> +	u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
> >> +	u32 hap = 0;
> >> +	int i;
> >> +
> >> +	for (i = 0; i < nr_apr_regs; i++) {
> >> +		u32 ap0, ap1;
> >> +		int c0, c1;
> >> +
> >> +		ap0 = __vgic_v3_read_ap0rn(i);
> >> +		ap1 = __vgic_v3_read_ap1rn(i);
> > 
> > so reading a group 1 interrupt from the IAR and writing that value back
> > to the EOIR1_EL1 register can somehow clear the priority of a group 0
> > interrupt?
> 
> If you properly nest the IAR and EOI, nothing bad will happen (group
> priorities are not supposed to overlap). If you decide to do weird
> things, you'll be in UNPREDICTABLE territory, and some interrupts can be
> left active while you deactivate the wrong one.
> 
> > Or did you just want a generic function that does what it's supposed to
> > regardless of which register was written to etc.?
> 
> That's the goal indeed.
> 
> > 
> >> +		if (!ap0 && !ap1) {
> >> +			hap += 32;
> >> +			continue;
> >> +		}
> >> +
> >> +		c0 = ap0 ? __ffs(ap0) : 32;
> >> +		c1 = ap1 ? __ffs(ap1) : 32;
> >> +
> >> +		/* Always clear the LSB, which is the highest priority */
> >> +		if (c0 < c1) {
> >> +			ap0 &= ~BIT(c0);
> >> +			__vgic_v3_write_ap0rn(ap0, i);
> >> +			hap += c0;
> >> +		} else {
> >> +			ap1 &= ~BIT(c1);
> >> +			__vgic_v3_write_ap1rn(ap1, i);
> >> +			hap += c1;
> > 
> > Can we ever have a situation where c0 == c1?  And in that case, should
> > you prioritize clearing the group 1 apr ?
> 
> You shouldn't ever have this case. The spec says:
> 
> "Having the bit corresponding to a priority set to 1 in both
> ICH_AP0R<n>_EL2 and ICH_AP1R<n>_EL2 might result in UNPREDICTABLE
> behavior of the interrupt prioritization system for virtual interrupts."
> 

ok, so the guest is just doing weird things, and because we're just
mediating the access to the hardware that the guest would normally have
at EL1, even though we're doing stuff from EL2, the hardware should
still be sane enough to never hurt the host.

> >> +		}
> >> +
> >> +		/* Rescale to 8 bits of priority */
> >> +		return hap << (8 - nr_pre_bits);
> >> +	}
> >> +
> >> +	return GICv3_IDLE_PRIORITY;
> >> +}
> >> +
> >>  static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >>  {
> >>  	u64 lr_val;
> >> @@ -542,6 +601,65 @@ static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int r
> >>  	vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS);
> >>  }
> >>  
> >> +static void __hyp_text __vgic_v3_clear_active_lr(int lr, u64 lr_val)
> >> +{
> >> +	lr_val &= ~ICH_LR_ACTIVE_BIT;
> >> +	if (lr_val & ICH_LR_HW) {
> >> +		u32 pid;
> >> +
> >> +		pid = (lr_val & ICH_LR_PHYS_ID_MASK) >> ICH_LR_PHYS_ID_SHIFT;
> >> +		gic_write_dir(pid);
> > 
> > Yikes, scary.  I can't think of this breaking anything.  But, scary.
> 
> I know. a (slightly) less scary approach would be to go all the way back
> to EL1 and to the DIR write there, but I don't thing this buys us
> anything but wasted cycles...
> 

No, it should end up being the same, so no reason to bother.

> > 
> >> +	}
> >> +
> >> +	__gic_v3_set_lr(lr_val, lr);
> >> +}
> >> +
> >> +static void __hyp_text __vgic_v3_bump_eoicount(void)
> >> +{
> >> +	u32 hcr;
> >> +
> >> +	hcr = read_gicreg(ICH_HCR_EL2);
> >> +	hcr += 1 << ICH_HCR_EOIcount_SHIFT;
> >> +	write_gicreg(hcr, ICH_HCR_EL2);
> >> +}
> >> +
> >> +static void __hyp_text __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >> +{
> >> +	u32 vid = vcpu_get_reg(vcpu, rt);
> >> +	u64 lr_val;
> >> +	u8 lr_prio, act_prio;
> >> +	int lr, grp;
> >> +
> >> +	grp = __vgic_v3_get_group(vcpu);
> >> +
> >> +	/* Drop priority in any case */
> >> +	act_prio = __vgic_v3_clear_highest_active_priority();
> >> +
> >> +	/* If EOIing an LPI, no deactivate to be performed */
> >> +	if (vid >= VGIC_MIN_LPI)
> >> +		return;
> >> +
> >> +	/* EOImode == 1, nothing to be done here */
> >> +	if (vmcr & ICH_VMCR_EOIM_MASK)
> >> +		return;
> >> +
> >> +	lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val);
> >> +	if (lr == -1) {
> >> +		__vgic_v3_bump_eoicount();
> >> +		return;
> >> +	}
> >> +
> >> +	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
> >> +
> >> +	/* If priorities or group do not match, the guest has fscked-up. */
> >> +	if (grp != !!(lr_val & ICH_LR_GROUP) ||
> >> +	    __vgic_v3_pri_to_pre(lr_prio, vmcr, grp) != act_prio)
> >> +		return;
> > 
> > Since we've cleared the highest priority above, is there any way for the
> > guest to recover from this, or do this particular (v)GIC implementation
> > have the implementation defined behavior of a write with something else
> > than the last valid read from the IAR of the same group to the EOIR
> > means that the system is toast?
> 
> The only way to recover from such a situation from a guest PoV is to
> write its APRs to zero, turn everything off, reset the whole GIC, and
> restart from scratch. Not pleasant...
> 
ok, fair enough, the guest asked for it, we give it.

Thanks,
-Christoffer

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

* Re: [PATCH v2 06/25] KVM: arm64: vgic-v3: Add ICV_IGRPEN1_EL1 handler
  2017-06-01 10:20   ` Marc Zyngier
@ 2017-06-06 13:22     ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:22 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On Thu, Jun 01, 2017 at 11:20:58AM +0100, Marc Zyngier wrote:
> Add a handler for reading/writing the guest's view of the ICC_IGRPEN1_EL1
> register, which is located in the ICH_VMCR_EL2.VENG1 field.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Reviewed-by: Christoffer Dall <cdall@linaro.org>

> ---
>  virt/kvm/arm/hyp/vgic-v3-sr.c | 23 +++++++++++++++++++++++
>  1 file changed, 23 insertions(+)
> 
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 6254eaf72a77..168539dfd0b9 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -395,6 +395,23 @@ static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
>  	return bpr;
>  }
>  
> +static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> +{
> +	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
> +}
> +
> +static void __hyp_text __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> +{
> +	u64 val = vcpu_get_reg(vcpu, rt);
> +
> +	if (val & 1)
> +		vmcr |= ICH_VMCR_ENG1_MASK;
> +	else
> +		vmcr &= ~ICH_VMCR_ENG1_MASK;
> +
> +	__vgic_v3_write_vmcr(vmcr);
> +}
> +
>  static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  {
>  	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
> @@ -442,6 +459,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
>  
>  	switch (sysreg) {
> +	case SYS_ICC_GRPEN1_EL1:
> +		if (is_read)
> +			fn = __vgic_v3_read_igrpen1;
> +		else
> +			fn = __vgic_v3_write_igrpen1;
> +		break;
>  	case SYS_ICC_BPR1_EL1:
>  		if (is_read)
>  			fn = __vgic_v3_read_bpr1;
> -- 
> 2.11.0
> 

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

* [PATCH v2 06/25] KVM: arm64: vgic-v3: Add ICV_IGRPEN1_EL1 handler
@ 2017-06-06 13:22     ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 01, 2017 at 11:20:58AM +0100, Marc Zyngier wrote:
> Add a handler for reading/writing the guest's view of the ICC_IGRPEN1_EL1
> register, which is located in the ICH_VMCR_EL2.VENG1 field.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Reviewed-by: Christoffer Dall <cdall@linaro.org>

> ---
>  virt/kvm/arm/hyp/vgic-v3-sr.c | 23 +++++++++++++++++++++++
>  1 file changed, 23 insertions(+)
> 
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 6254eaf72a77..168539dfd0b9 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -395,6 +395,23 @@ static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
>  	return bpr;
>  }
>  
> +static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> +{
> +	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
> +}
> +
> +static void __hyp_text __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> +{
> +	u64 val = vcpu_get_reg(vcpu, rt);
> +
> +	if (val & 1)
> +		vmcr |= ICH_VMCR_ENG1_MASK;
> +	else
> +		vmcr &= ~ICH_VMCR_ENG1_MASK;
> +
> +	__vgic_v3_write_vmcr(vmcr);
> +}
> +
>  static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  {
>  	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
> @@ -442,6 +459,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
>  
>  	switch (sysreg) {
> +	case SYS_ICC_GRPEN1_EL1:
> +		if (is_read)
> +			fn = __vgic_v3_read_igrpen1;
> +		else
> +			fn = __vgic_v3_write_igrpen1;
> +		break;
>  	case SYS_ICC_BPR1_EL1:
>  		if (is_read)
>  			fn = __vgic_v3_read_bpr1;
> -- 
> 2.11.0
> 

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

* Re: [PATCH v2 09/25] KVM: arm64: vgic-v3: Add ICV_AP1Rn_EL1 handler
  2017-06-01 10:21   ` Marc Zyngier
@ 2017-06-06 13:22     ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:22 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On Thu, Jun 01, 2017 at 11:21:01AM +0100, Marc Zyngier wrote:
> Add a handler for reading/writing the guest's view of the ICV_AP1Rn_EL1
> registers. We just map them to the corresponding ICH_AP1Rn_EL2 registers.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Reviewed-by: Christoffer Dall <cdall@linaro.org>

> ---
>  arch/arm64/include/asm/sysreg.h |  1 +
>  virt/kvm/arm/hyp/vgic-v3-sr.c   | 94 +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 95 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index 15c142ce991c..aad46b8eea5e 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -180,6 +180,7 @@
>  
>  #define SYS_VBAR_EL1			sys_reg(3, 0, 12, 0, 0)
>  
> +#define SYS_ICC_AP1Rn_EL1(n)		sys_reg(3, 0, 12, 9, n)
>  #define SYS_ICC_DIR_EL1			sys_reg(3, 0, 12, 11, 1)
>  #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
>  #define SYS_ICC_IAR1_EL1		sys_reg(3, 0, 12, 12, 0)
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 3f04122a5d4d..d4f07f84602d 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -702,6 +702,76 @@ static void __hyp_text __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int
>  	__vgic_v3_write_vmcr(vmcr);
>  }
>  
> +static void __hyp_text __vgic_v3_read_apxrn(struct kvm_vcpu *vcpu, int rt, int n)
> +{
> +	u32 val;
> +
> +	if (!__vgic_v3_get_group(vcpu))
> +		val = __vgic_v3_read_ap0rn(n);
> +	else
> +		val = __vgic_v3_read_ap1rn(n);
> +
> +	vcpu_set_reg(vcpu, rt, val);
> +}
> +
> +static void __hyp_text __vgic_v3_write_apxrn(struct kvm_vcpu *vcpu, int rt, int n)
> +{
> +	u32 val = vcpu_get_reg(vcpu, rt);
> +
> +	if (!__vgic_v3_get_group(vcpu))
> +		__vgic_v3_write_ap0rn(val, n);
> +	else
> +		__vgic_v3_write_ap1rn(val, n);
> +}
> +
> +static void __hyp_text __vgic_v3_read_apxr0(struct kvm_vcpu *vcpu,
> +					    u32 vmcr, int rt)
> +{
> +	__vgic_v3_read_apxrn(vcpu, rt, 0);
> +}
> +
> +static void __hyp_text __vgic_v3_read_apxr1(struct kvm_vcpu *vcpu,
> +					    u32 vmcr, int rt)
> +{
> +	__vgic_v3_read_apxrn(vcpu, rt, 1);
> +}
> +
> +static void __hyp_text __vgic_v3_read_apxr2(struct kvm_vcpu *vcpu,
> +					    u32 vmcr, int rt)
> +{
> +	__vgic_v3_read_apxrn(vcpu, rt, 2);
> +}
> +
> +static void __hyp_text __vgic_v3_read_apxr3(struct kvm_vcpu *vcpu,
> +					    u32 vmcr, int rt)
> +{
> +	__vgic_v3_read_apxrn(vcpu, rt, 3);
> +}
> +
> +static void __hyp_text __vgic_v3_write_apxr0(struct kvm_vcpu *vcpu,
> +					     u32 vmcr, int rt)
> +{
> +	__vgic_v3_write_apxrn(vcpu, rt, 0);
> +}
> +
> +static void __hyp_text __vgic_v3_write_apxr1(struct kvm_vcpu *vcpu,
> +					     u32 vmcr, int rt)
> +{
> +	__vgic_v3_write_apxrn(vcpu, rt, 1);
> +}
> +
> +static void __hyp_text __vgic_v3_write_apxr2(struct kvm_vcpu *vcpu,
> +					     u32 vmcr, int rt)
> +{
> +	__vgic_v3_write_apxrn(vcpu, rt, 2);
> +}
> +
> +static void __hyp_text __vgic_v3_write_apxr3(struct kvm_vcpu *vcpu,
> +					     u32 vmcr, int rt)
> +{
> +	__vgic_v3_write_apxrn(vcpu, rt, 3);
> +}
> +
>  int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  {
>  	int rt;
> @@ -742,6 +812,30 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  		else
>  			fn = __vgic_v3_write_bpr1;
>  		break;
> +	case SYS_ICC_AP1Rn_EL1(0):
> +		if (is_read)
> +			fn = __vgic_v3_read_apxr0;
> +		else
> +			fn = __vgic_v3_write_apxr0;
> +		break;
> +	case SYS_ICC_AP1Rn_EL1(1):
> +		if (is_read)
> +			fn = __vgic_v3_read_apxr1;
> +		else
> +			fn = __vgic_v3_write_apxr1;
> +		break;
> +	case SYS_ICC_AP1Rn_EL1(2):
> +		if (is_read)
> +			fn = __vgic_v3_read_apxr2;
> +		else
> +			fn = __vgic_v3_write_apxr2;
> +		break;
> +	case SYS_ICC_AP1Rn_EL1(3):
> +		if (is_read)
> +			fn = __vgic_v3_read_apxr3;
> +		else
> +			fn = __vgic_v3_write_apxr3;
> +		break;
>  	default:
>  		return 0;
>  	}
> -- 
> 2.11.0
> 

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

* [PATCH v2 09/25] KVM: arm64: vgic-v3: Add ICV_AP1Rn_EL1 handler
@ 2017-06-06 13:22     ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 01, 2017 at 11:21:01AM +0100, Marc Zyngier wrote:
> Add a handler for reading/writing the guest's view of the ICV_AP1Rn_EL1
> registers. We just map them to the corresponding ICH_AP1Rn_EL2 registers.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Reviewed-by: Christoffer Dall <cdall@linaro.org>

> ---
>  arch/arm64/include/asm/sysreg.h |  1 +
>  virt/kvm/arm/hyp/vgic-v3-sr.c   | 94 +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 95 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index 15c142ce991c..aad46b8eea5e 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -180,6 +180,7 @@
>  
>  #define SYS_VBAR_EL1			sys_reg(3, 0, 12, 0, 0)
>  
> +#define SYS_ICC_AP1Rn_EL1(n)		sys_reg(3, 0, 12, 9, n)
>  #define SYS_ICC_DIR_EL1			sys_reg(3, 0, 12, 11, 1)
>  #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
>  #define SYS_ICC_IAR1_EL1		sys_reg(3, 0, 12, 12, 0)
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 3f04122a5d4d..d4f07f84602d 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -702,6 +702,76 @@ static void __hyp_text __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int
>  	__vgic_v3_write_vmcr(vmcr);
>  }
>  
> +static void __hyp_text __vgic_v3_read_apxrn(struct kvm_vcpu *vcpu, int rt, int n)
> +{
> +	u32 val;
> +
> +	if (!__vgic_v3_get_group(vcpu))
> +		val = __vgic_v3_read_ap0rn(n);
> +	else
> +		val = __vgic_v3_read_ap1rn(n);
> +
> +	vcpu_set_reg(vcpu, rt, val);
> +}
> +
> +static void __hyp_text __vgic_v3_write_apxrn(struct kvm_vcpu *vcpu, int rt, int n)
> +{
> +	u32 val = vcpu_get_reg(vcpu, rt);
> +
> +	if (!__vgic_v3_get_group(vcpu))
> +		__vgic_v3_write_ap0rn(val, n);
> +	else
> +		__vgic_v3_write_ap1rn(val, n);
> +}
> +
> +static void __hyp_text __vgic_v3_read_apxr0(struct kvm_vcpu *vcpu,
> +					    u32 vmcr, int rt)
> +{
> +	__vgic_v3_read_apxrn(vcpu, rt, 0);
> +}
> +
> +static void __hyp_text __vgic_v3_read_apxr1(struct kvm_vcpu *vcpu,
> +					    u32 vmcr, int rt)
> +{
> +	__vgic_v3_read_apxrn(vcpu, rt, 1);
> +}
> +
> +static void __hyp_text __vgic_v3_read_apxr2(struct kvm_vcpu *vcpu,
> +					    u32 vmcr, int rt)
> +{
> +	__vgic_v3_read_apxrn(vcpu, rt, 2);
> +}
> +
> +static void __hyp_text __vgic_v3_read_apxr3(struct kvm_vcpu *vcpu,
> +					    u32 vmcr, int rt)
> +{
> +	__vgic_v3_read_apxrn(vcpu, rt, 3);
> +}
> +
> +static void __hyp_text __vgic_v3_write_apxr0(struct kvm_vcpu *vcpu,
> +					     u32 vmcr, int rt)
> +{
> +	__vgic_v3_write_apxrn(vcpu, rt, 0);
> +}
> +
> +static void __hyp_text __vgic_v3_write_apxr1(struct kvm_vcpu *vcpu,
> +					     u32 vmcr, int rt)
> +{
> +	__vgic_v3_write_apxrn(vcpu, rt, 1);
> +}
> +
> +static void __hyp_text __vgic_v3_write_apxr2(struct kvm_vcpu *vcpu,
> +					     u32 vmcr, int rt)
> +{
> +	__vgic_v3_write_apxrn(vcpu, rt, 2);
> +}
> +
> +static void __hyp_text __vgic_v3_write_apxr3(struct kvm_vcpu *vcpu,
> +					     u32 vmcr, int rt)
> +{
> +	__vgic_v3_write_apxrn(vcpu, rt, 3);
> +}
> +
>  int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  {
>  	int rt;
> @@ -742,6 +812,30 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  		else
>  			fn = __vgic_v3_write_bpr1;
>  		break;
> +	case SYS_ICC_AP1Rn_EL1(0):
> +		if (is_read)
> +			fn = __vgic_v3_read_apxr0;
> +		else
> +			fn = __vgic_v3_write_apxr0;
> +		break;
> +	case SYS_ICC_AP1Rn_EL1(1):
> +		if (is_read)
> +			fn = __vgic_v3_read_apxr1;
> +		else
> +			fn = __vgic_v3_write_apxr1;
> +		break;
> +	case SYS_ICC_AP1Rn_EL1(2):
> +		if (is_read)
> +			fn = __vgic_v3_read_apxr2;
> +		else
> +			fn = __vgic_v3_write_apxr2;
> +		break;
> +	case SYS_ICC_AP1Rn_EL1(3):
> +		if (is_read)
> +			fn = __vgic_v3_read_apxr3;
> +		else
> +			fn = __vgic_v3_write_apxr3;
> +		break;
>  	default:
>  		return 0;
>  	}
> -- 
> 2.11.0
> 

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

* Re: [PATCH v2 11/25] KVM: arm64: vgic-v3: Enable trapping of Group-1 system registers
  2017-06-01 10:21   ` Marc Zyngier
@ 2017-06-06 13:22     ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:22 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On Thu, Jun 01, 2017 at 11:21:03AM +0100, Marc Zyngier wrote:
> In order to be able to trap Group-1 GICv3 system registers, we need to
> set ICH_HCR_EL2.TALL1 before entering the guest. This is conditionally
> done after having restored the guest's state, and cleared on exit.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Acked-by: Christoffer Dall <cdall@linaro.org>

> ---
>  include/linux/irqchip/arm-gic-v3.h | 1 +
>  virt/kvm/arm/hyp/vgic-v3-sr.c      | 7 +++++++
>  virt/kvm/arm/vgic/vgic-v3.c        | 4 ++++
>  3 files changed, 12 insertions(+)
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index e50ce5d416a3..03b5a28bb2d0 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -417,6 +417,7 @@
>  
>  #define ICH_HCR_EN			(1 << 0)
>  #define ICH_HCR_UIE			(1 << 1)
> +#define ICH_HCR_TALL1			(1 << 12)
>  #define ICH_HCR_EOIcount_SHIFT		27
>  #define ICH_HCR_EOIcount_MASK		(0x1f << ICH_HCR_EOIcount_SHIFT)
>  
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index f0bc711db258..8973bad35748 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -258,6 +258,9 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
>  			cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0);
>  		}
>  	} else {
> +		if (static_branch_unlikely(&vgic_v3_cpuif_trap))
> +			write_gicreg(0, ICH_HCR_EL2);
> +
>  		cpu_if->vgic_elrsr = 0xffff;
>  		cpu_if->vgic_ap0r[0] = 0;
>  		cpu_if->vgic_ap0r[1] = 0;
> @@ -330,6 +333,10 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
>  
>  		for (i = 0; i < used_lrs; i++)
>  			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
> +	} else {
> +		/* Always write ICH_HCR_EL2 to enable trapping */
> +		if (static_branch_unlikely(&vgic_v3_cpuif_trap))
> +			write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
>  	}
>  
>  	/*
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 88d9bd9bf468..fbd678bc046d 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -21,6 +21,8 @@
>  
>  #include "vgic.h"
>  
> +static bool group1_trap;
> +
>  void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>  {
>  	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> @@ -239,6 +241,8 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
>  
>  	/* Get the show on the road... */
>  	vgic_v3->vgic_hcr = ICH_HCR_EN;
> +	if (group1_trap)
> +		vgic_v3->vgic_hcr |= ICH_HCR_TALL1;
>  }
>  
>  int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq)
> -- 
> 2.11.0
> 

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

* [PATCH v2 11/25] KVM: arm64: vgic-v3: Enable trapping of Group-1 system registers
@ 2017-06-06 13:22     ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 01, 2017 at 11:21:03AM +0100, Marc Zyngier wrote:
> In order to be able to trap Group-1 GICv3 system registers, we need to
> set ICH_HCR_EL2.TALL1 before entering the guest. This is conditionally
> done after having restored the guest's state, and cleared on exit.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Acked-by: Christoffer Dall <cdall@linaro.org>

> ---
>  include/linux/irqchip/arm-gic-v3.h | 1 +
>  virt/kvm/arm/hyp/vgic-v3-sr.c      | 7 +++++++
>  virt/kvm/arm/vgic/vgic-v3.c        | 4 ++++
>  3 files changed, 12 insertions(+)
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index e50ce5d416a3..03b5a28bb2d0 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -417,6 +417,7 @@
>  
>  #define ICH_HCR_EN			(1 << 0)
>  #define ICH_HCR_UIE			(1 << 1)
> +#define ICH_HCR_TALL1			(1 << 12)
>  #define ICH_HCR_EOIcount_SHIFT		27
>  #define ICH_HCR_EOIcount_MASK		(0x1f << ICH_HCR_EOIcount_SHIFT)
>  
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index f0bc711db258..8973bad35748 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -258,6 +258,9 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
>  			cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0);
>  		}
>  	} else {
> +		if (static_branch_unlikely(&vgic_v3_cpuif_trap))
> +			write_gicreg(0, ICH_HCR_EL2);
> +
>  		cpu_if->vgic_elrsr = 0xffff;
>  		cpu_if->vgic_ap0r[0] = 0;
>  		cpu_if->vgic_ap0r[1] = 0;
> @@ -330,6 +333,10 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
>  
>  		for (i = 0; i < used_lrs; i++)
>  			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
> +	} else {
> +		/* Always write ICH_HCR_EL2 to enable trapping */
> +		if (static_branch_unlikely(&vgic_v3_cpuif_trap))
> +			write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
>  	}
>  
>  	/*
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 88d9bd9bf468..fbd678bc046d 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -21,6 +21,8 @@
>  
>  #include "vgic.h"
>  
> +static bool group1_trap;
> +
>  void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
>  {
>  	struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
> @@ -239,6 +241,8 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
>  
>  	/* Get the show on the road... */
>  	vgic_v3->vgic_hcr = ICH_HCR_EN;
> +	if (group1_trap)
> +		vgic_v3->vgic_hcr |= ICH_HCR_TALL1;
>  }
>  
>  int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq)
> -- 
> 2.11.0
> 

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

* Re: [PATCH v2 14/25] KVM: arm64: vgic-v3: Add ICV_IGNREN0_EL1 handler
  2017-06-01 10:21   ` Marc Zyngier
@ 2017-06-06 13:22     ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:22 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter,
	linux-arm-kernel, kvmarm

On Thu, Jun 01, 2017 at 11:21:06AM +0100, Marc Zyngier wrote:
> Add a handler for reading/writing the guest's view of the ICC_IGRPEN0_EL1
> register, which is located in the ICH_VMCR_EL2.VENG0 field.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Reviewed-by: Christoffer Dall <cdall@linaro.org>

> ---
>  arch/arm64/include/asm/sysreg.h |  1 +
>  virt/kvm/arm/hyp/vgic-v3-sr.c   | 23 +++++++++++++++++++++++
>  2 files changed, 24 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index d20be0b28ca4..ba93bc7ac8e4 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -190,6 +190,7 @@
>  #define SYS_ICC_BPR1_EL1		sys_reg(3, 0, 12, 12, 3)
>  #define SYS_ICC_CTLR_EL1		sys_reg(3, 0, 12, 12, 4)
>  #define SYS_ICC_SRE_EL1			sys_reg(3, 0, 12, 12, 5)
> +#define SYS_ICC_GRPEN0_EL1		sys_reg(3, 0, 12, 12, 6)
>  #define SYS_ICC_GRPEN1_EL1		sys_reg(3, 0, 12, 12, 7)
>  
>  #define SYS_CONTEXTIDR_EL1		sys_reg(3, 0, 13, 0, 1)
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 54a8e828c85b..b1b9129da045 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -671,11 +671,28 @@ static void __hyp_text __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int
>  	__vgic_v3_clear_active_lr(lr, lr_val);
>  }
>  
> +static void __hyp_text __vgic_v3_read_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> +{
> +	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG0_MASK));
> +}
> +
>  static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  {
>  	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
>  }
>  
> +static void __hyp_text __vgic_v3_write_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> +{
> +	u64 val = vcpu_get_reg(vcpu, rt);
> +
> +	if (val & 1)
> +		vmcr |= ICH_VMCR_ENG0_MASK;
> +	else
> +		vmcr &= ~ICH_VMCR_ENG0_MASK;
> +
> +	__vgic_v3_write_vmcr(vmcr);
> +}
> +
>  static void __hyp_text __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  {
>  	u64 val = vcpu_get_reg(vcpu, rt);
> @@ -900,6 +917,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  	case SYS_ICC_HPPIR1_EL1:
>  		fn = __vgic_v3_read_hppir;
>  		break;
> +	case SYS_ICC_GRPEN0_EL1:
> +		if (is_read)
> +			fn = __vgic_v3_read_igrpen0;
> +		else
> +			fn = __vgic_v3_write_igrpen0;
> +		break;
>  	case SYS_ICC_BPR0_EL1:
>  		if (is_read)
>  			fn = __vgic_v3_read_bpr0;
> -- 
> 2.11.0
> 

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

* [PATCH v2 14/25] KVM: arm64: vgic-v3: Add ICV_IGNREN0_EL1 handler
@ 2017-06-06 13:22     ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 01, 2017 at 11:21:06AM +0100, Marc Zyngier wrote:
> Add a handler for reading/writing the guest's view of the ICC_IGRPEN0_EL1
> register, which is located in the ICH_VMCR_EL2.VENG0 field.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Reviewed-by: Christoffer Dall <cdall@linaro.org>

> ---
>  arch/arm64/include/asm/sysreg.h |  1 +
>  virt/kvm/arm/hyp/vgic-v3-sr.c   | 23 +++++++++++++++++++++++
>  2 files changed, 24 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index d20be0b28ca4..ba93bc7ac8e4 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -190,6 +190,7 @@
>  #define SYS_ICC_BPR1_EL1		sys_reg(3, 0, 12, 12, 3)
>  #define SYS_ICC_CTLR_EL1		sys_reg(3, 0, 12, 12, 4)
>  #define SYS_ICC_SRE_EL1			sys_reg(3, 0, 12, 12, 5)
> +#define SYS_ICC_GRPEN0_EL1		sys_reg(3, 0, 12, 12, 6)
>  #define SYS_ICC_GRPEN1_EL1		sys_reg(3, 0, 12, 12, 7)
>  
>  #define SYS_CONTEXTIDR_EL1		sys_reg(3, 0, 13, 0, 1)
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 54a8e828c85b..b1b9129da045 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -671,11 +671,28 @@ static void __hyp_text __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int
>  	__vgic_v3_clear_active_lr(lr, lr_val);
>  }
>  
> +static void __hyp_text __vgic_v3_read_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> +{
> +	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG0_MASK));
> +}
> +
>  static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  {
>  	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
>  }
>  
> +static void __hyp_text __vgic_v3_write_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> +{
> +	u64 val = vcpu_get_reg(vcpu, rt);
> +
> +	if (val & 1)
> +		vmcr |= ICH_VMCR_ENG0_MASK;
> +	else
> +		vmcr &= ~ICH_VMCR_ENG0_MASK;
> +
> +	__vgic_v3_write_vmcr(vmcr);
> +}
> +
>  static void __hyp_text __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>  {
>  	u64 val = vcpu_get_reg(vcpu, rt);
> @@ -900,6 +917,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  	case SYS_ICC_HPPIR1_EL1:
>  		fn = __vgic_v3_read_hppir;
>  		break;
> +	case SYS_ICC_GRPEN0_EL1:
> +		if (is_read)
> +			fn = __vgic_v3_read_igrpen0;
> +		else
> +			fn = __vgic_v3_write_igrpen0;
> +		break;
>  	case SYS_ICC_BPR0_EL1:
>  		if (is_read)
>  			fn = __vgic_v3_read_bpr0;
> -- 
> 2.11.0
> 

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

* Re: [PATCH v2 15/25] KVM: arm64: vgic-v3: Add misc Group-0 handlers
  2017-06-01 10:21   ` Marc Zyngier
@ 2017-06-06 13:22     ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:22 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter,
	linux-arm-kernel, kvmarm

On Thu, Jun 01, 2017 at 11:21:07AM +0100, Marc Zyngier wrote:
> A number of Group-0 registers can be handled by the same accessors
> as that of Group-1, so let's add the required system register encodings
> and catch them in the dispatching function.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Acked-by: Christoffer Dall <cdall@linaro.org>

> ---
>  arch/arm64/include/asm/sysreg.h | 4 ++++
>  virt/kvm/arm/hyp/vgic-v3-sr.c   | 7 +++++++
>  2 files changed, 11 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index ba93bc7ac8e4..9971c5c435a7 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -180,7 +180,11 @@
>  
>  #define SYS_VBAR_EL1			sys_reg(3, 0, 12, 0, 0)
>  
> +#define SYS_ICC_IAR0_EL1		sys_reg(3, 0, 12, 8, 0)
> +#define SYS_ICC_EOIR0_EL1		sys_reg(3, 0, 12, 8, 1)
> +#define SYS_ICC_HPPIR0_EL1		sys_reg(3, 0, 12, 8, 2)
>  #define SYS_ICC_BPR0_EL1		sys_reg(3, 0, 12, 8, 3)
> +#define SYS_ICC_AP0Rn_EL1(n)		sys_reg(3, 0, 12, 8, 4 | n)
>  #define SYS_ICC_AP1Rn_EL1(n)		sys_reg(3, 0, 12, 9, n)
>  #define SYS_ICC_DIR_EL1			sys_reg(3, 0, 12, 11, 1)
>  #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index b1b9129da045..5ff788d308ee 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -872,9 +872,11 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
>  
>  	switch (sysreg) {
> +	case SYS_ICC_IAR0_EL1:
>  	case SYS_ICC_IAR1_EL1:
>  		fn = __vgic_v3_read_iar;
>  		break;
> +	case SYS_ICC_EOIR0_EL1:
>  	case SYS_ICC_EOIR1_EL1:
>  		fn = __vgic_v3_write_eoir;
>  		break;
> @@ -890,30 +892,35 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  		else
>  			fn = __vgic_v3_write_bpr1;
>  		break;
> +	case SYS_ICC_AP0Rn_EL1(0):
>  	case SYS_ICC_AP1Rn_EL1(0):
>  		if (is_read)
>  			fn = __vgic_v3_read_apxr0;
>  		else
>  			fn = __vgic_v3_write_apxr0;
>  		break;
> +	case SYS_ICC_AP0Rn_EL1(1):
>  	case SYS_ICC_AP1Rn_EL1(1):
>  		if (is_read)
>  			fn = __vgic_v3_read_apxr1;
>  		else
>  			fn = __vgic_v3_write_apxr1;
>  		break;
> +	case SYS_ICC_AP0Rn_EL1(2):
>  	case SYS_ICC_AP1Rn_EL1(2):
>  		if (is_read)
>  			fn = __vgic_v3_read_apxr2;
>  		else
>  			fn = __vgic_v3_write_apxr2;
>  		break;
> +	case SYS_ICC_AP0Rn_EL1(3):
>  	case SYS_ICC_AP1Rn_EL1(3):
>  		if (is_read)
>  			fn = __vgic_v3_read_apxr3;
>  		else
>  			fn = __vgic_v3_write_apxr3;
>  		break;
> +	case SYS_ICC_HPPIR0_EL1:
>  	case SYS_ICC_HPPIR1_EL1:
>  		fn = __vgic_v3_read_hppir;
>  		break;
> -- 
> 2.11.0
> 

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

* [PATCH v2 15/25] KVM: arm64: vgic-v3: Add misc Group-0 handlers
@ 2017-06-06 13:22     ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 01, 2017 at 11:21:07AM +0100, Marc Zyngier wrote:
> A number of Group-0 registers can be handled by the same accessors
> as that of Group-1, so let's add the required system register encodings
> and catch them in the dispatching function.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Acked-by: Christoffer Dall <cdall@linaro.org>

> ---
>  arch/arm64/include/asm/sysreg.h | 4 ++++
>  virt/kvm/arm/hyp/vgic-v3-sr.c   | 7 +++++++
>  2 files changed, 11 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index ba93bc7ac8e4..9971c5c435a7 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -180,7 +180,11 @@
>  
>  #define SYS_VBAR_EL1			sys_reg(3, 0, 12, 0, 0)
>  
> +#define SYS_ICC_IAR0_EL1		sys_reg(3, 0, 12, 8, 0)
> +#define SYS_ICC_EOIR0_EL1		sys_reg(3, 0, 12, 8, 1)
> +#define SYS_ICC_HPPIR0_EL1		sys_reg(3, 0, 12, 8, 2)
>  #define SYS_ICC_BPR0_EL1		sys_reg(3, 0, 12, 8, 3)
> +#define SYS_ICC_AP0Rn_EL1(n)		sys_reg(3, 0, 12, 8, 4 | n)
>  #define SYS_ICC_AP1Rn_EL1(n)		sys_reg(3, 0, 12, 9, n)
>  #define SYS_ICC_DIR_EL1			sys_reg(3, 0, 12, 11, 1)
>  #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index b1b9129da045..5ff788d308ee 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -872,9 +872,11 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
>  
>  	switch (sysreg) {
> +	case SYS_ICC_IAR0_EL1:
>  	case SYS_ICC_IAR1_EL1:
>  		fn = __vgic_v3_read_iar;
>  		break;
> +	case SYS_ICC_EOIR0_EL1:
>  	case SYS_ICC_EOIR1_EL1:
>  		fn = __vgic_v3_write_eoir;
>  		break;
> @@ -890,30 +892,35 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  		else
>  			fn = __vgic_v3_write_bpr1;
>  		break;
> +	case SYS_ICC_AP0Rn_EL1(0):
>  	case SYS_ICC_AP1Rn_EL1(0):
>  		if (is_read)
>  			fn = __vgic_v3_read_apxr0;
>  		else
>  			fn = __vgic_v3_write_apxr0;
>  		break;
> +	case SYS_ICC_AP0Rn_EL1(1):
>  	case SYS_ICC_AP1Rn_EL1(1):
>  		if (is_read)
>  			fn = __vgic_v3_read_apxr1;
>  		else
>  			fn = __vgic_v3_write_apxr1;
>  		break;
> +	case SYS_ICC_AP0Rn_EL1(2):
>  	case SYS_ICC_AP1Rn_EL1(2):
>  		if (is_read)
>  			fn = __vgic_v3_read_apxr2;
>  		else
>  			fn = __vgic_v3_write_apxr2;
>  		break;
> +	case SYS_ICC_AP0Rn_EL1(3):
>  	case SYS_ICC_AP1Rn_EL1(3):
>  		if (is_read)
>  			fn = __vgic_v3_read_apxr3;
>  		else
>  			fn = __vgic_v3_write_apxr3;
>  		break;
> +	case SYS_ICC_HPPIR0_EL1:
>  	case SYS_ICC_HPPIR1_EL1:
>  		fn = __vgic_v3_read_hppir;
>  		break;
> -- 
> 2.11.0
> 

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

* Re: [PATCH v2 16/25] KVM: arm64: vgic-v3: Enable trapping of Group-0 system registers
  2017-06-01 10:21   ` Marc Zyngier
@ 2017-06-06 13:22     ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:22 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On Thu, Jun 01, 2017 at 11:21:08AM +0100, Marc Zyngier wrote:
> In order to be able to trap Group-0 GICv3 system registers, we need to
> set ICH_HCR_EL2.TALL0 begore entering the guest. This is conditionnaly
> done after having restored the guest's state, and cleared on exit.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Acked-by: Christoffer Dall <cdall@linaro.org>

> ---
>  include/linux/irqchip/arm-gic-v3.h | 1 +
>  virt/kvm/arm/vgic/vgic-v3.c        | 5 ++++-
>  2 files changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index 03b5a28bb2d0..46a1e0943cf8 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -417,6 +417,7 @@
>  
>  #define ICH_HCR_EN			(1 << 0)
>  #define ICH_HCR_UIE			(1 << 1)
> +#define ICH_HCR_TALL0			(1 << 11)
>  #define ICH_HCR_TALL1			(1 << 12)
>  #define ICH_HCR_EOIcount_SHIFT		27
>  #define ICH_HCR_EOIcount_MASK		(0x1f << ICH_HCR_EOIcount_SHIFT)
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index a16769276efd..7525216ef988 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -21,6 +21,7 @@
>  
>  #include "vgic.h"
>  
> +static bool group0_trap;
>  static bool group1_trap;
>  
>  void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> @@ -241,6 +242,8 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
>  
>  	/* Get the show on the road... */
>  	vgic_v3->vgic_hcr = ICH_HCR_EN;
> +	if (group0_trap)
> +		vgic_v3->vgic_hcr |= ICH_HCR_TALL0;
>  	if (group1_trap)
>  		vgic_v3->vgic_hcr |= ICH_HCR_TALL1;
>  }
> @@ -473,7 +476,7 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
>  	if (kvm_vgic_global_state.vcpu_base == 0)
>  		kvm_info("disabling GICv2 emulation\n");
>  
> -	if (group1_trap) {
> +	if (group0_trap || group1_trap) {
>  		kvm_info("GICv3 sysreg trapping enabled (reduced performance)\n");
>  		static_branch_enable(&vgic_v3_cpuif_trap);
>  	}
> -- 
> 2.11.0
> 

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

* [PATCH v2 16/25] KVM: arm64: vgic-v3: Enable trapping of Group-0 system registers
@ 2017-06-06 13:22     ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 01, 2017 at 11:21:08AM +0100, Marc Zyngier wrote:
> In order to be able to trap Group-0 GICv3 system registers, we need to
> set ICH_HCR_EL2.TALL0 begore entering the guest. This is conditionnaly
> done after having restored the guest's state, and cleared on exit.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Acked-by: Christoffer Dall <cdall@linaro.org>

> ---
>  include/linux/irqchip/arm-gic-v3.h | 1 +
>  virt/kvm/arm/vgic/vgic-v3.c        | 5 ++++-
>  2 files changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index 03b5a28bb2d0..46a1e0943cf8 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -417,6 +417,7 @@
>  
>  #define ICH_HCR_EN			(1 << 0)
>  #define ICH_HCR_UIE			(1 << 1)
> +#define ICH_HCR_TALL0			(1 << 11)
>  #define ICH_HCR_TALL1			(1 << 12)
>  #define ICH_HCR_EOIcount_SHIFT		27
>  #define ICH_HCR_EOIcount_MASK		(0x1f << ICH_HCR_EOIcount_SHIFT)
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index a16769276efd..7525216ef988 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -21,6 +21,7 @@
>  
>  #include "vgic.h"
>  
> +static bool group0_trap;
>  static bool group1_trap;
>  
>  void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
> @@ -241,6 +242,8 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu)
>  
>  	/* Get the show on the road... */
>  	vgic_v3->vgic_hcr = ICH_HCR_EN;
> +	if (group0_trap)
> +		vgic_v3->vgic_hcr |= ICH_HCR_TALL0;
>  	if (group1_trap)
>  		vgic_v3->vgic_hcr |= ICH_HCR_TALL1;
>  }
> @@ -473,7 +476,7 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
>  	if (kvm_vgic_global_state.vcpu_base == 0)
>  		kvm_info("disabling GICv2 emulation\n");
>  
> -	if (group1_trap) {
> +	if (group0_trap || group1_trap) {
>  		kvm_info("GICv3 sysreg trapping enabled (reduced performance)\n");
>  		static_branch_enable(&vgic_v3_cpuif_trap);
>  	}
> -- 
> 2.11.0
> 

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

* Re: [PATCH v2 21/25] KVM: arm64: vgic-v3: Add ICV_RPR_EL1 handler
  2017-06-01 10:21   ` Marc Zyngier
@ 2017-06-06 13:23     ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:23 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On Thu, Jun 01, 2017 at 11:21:13AM +0100, Marc Zyngier wrote:
> Add a handler for reading the guest's view of the ICV_RPR_EL1
> register, returning the highest active priority.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Acked-by: Christoffer Dall <cdall@linaro.org>

> ---
>  arch/arm64/include/asm/sysreg.h |  1 +
>  virt/kvm/arm/hyp/vgic-v3-sr.c   | 10 ++++++++++
>  2 files changed, 11 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index 9971c5c435a7..c4d48e403629 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -187,6 +187,7 @@
>  #define SYS_ICC_AP0Rn_EL1(n)		sys_reg(3, 0, 12, 8, 4 | n)
>  #define SYS_ICC_AP1Rn_EL1(n)		sys_reg(3, 0, 12, 9, n)
>  #define SYS_ICC_DIR_EL1			sys_reg(3, 0, 12, 11, 1)
> +#define SYS_ICC_RPR_EL1			sys_reg(3, 0, 12, 11, 3)
>  #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
>  #define SYS_ICC_IAR1_EL1		sys_reg(3, 0, 12, 12, 0)
>  #define SYS_ICC_EOIR1_EL1		sys_reg(3, 0, 12, 12, 1)
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index b86a0776c407..cac9d563d97d 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -874,6 +874,13 @@ static void __hyp_text __vgic_v3_read_hppir(struct kvm_vcpu *vcpu,
>  	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
>  }
>  
> +static void __hyp_text __vgic_v3_read_rpr(struct kvm_vcpu *vcpu,
> +					  u32 vmcr, int rt)
> +{
> +	u32 val = __vgic_v3_get_highest_active_priority();
> +	vcpu_set_reg(vcpu, rt, val);
> +}
> +
>  int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  {
>  	int rt;
> @@ -963,6 +970,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  	case SYS_ICC_DIR_EL1:
>  		fn = __vgic_v3_write_dir;
>  		break;
> +	case SYS_ICC_RPR_EL1:
> +		fn = __vgic_v3_read_rpr;
> +		break;
>  	default:
>  		return 0;
>  	}
> -- 
> 2.11.0
> 

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

* [PATCH v2 21/25] KVM: arm64: vgic-v3: Add ICV_RPR_EL1 handler
@ 2017-06-06 13:23     ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 01, 2017 at 11:21:13AM +0100, Marc Zyngier wrote:
> Add a handler for reading the guest's view of the ICV_RPR_EL1
> register, returning the highest active priority.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Acked-by: Christoffer Dall <cdall@linaro.org>

> ---
>  arch/arm64/include/asm/sysreg.h |  1 +
>  virt/kvm/arm/hyp/vgic-v3-sr.c   | 10 ++++++++++
>  2 files changed, 11 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index 9971c5c435a7..c4d48e403629 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -187,6 +187,7 @@
>  #define SYS_ICC_AP0Rn_EL1(n)		sys_reg(3, 0, 12, 8, 4 | n)
>  #define SYS_ICC_AP1Rn_EL1(n)		sys_reg(3, 0, 12, 9, n)
>  #define SYS_ICC_DIR_EL1			sys_reg(3, 0, 12, 11, 1)
> +#define SYS_ICC_RPR_EL1			sys_reg(3, 0, 12, 11, 3)
>  #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
>  #define SYS_ICC_IAR1_EL1		sys_reg(3, 0, 12, 12, 0)
>  #define SYS_ICC_EOIR1_EL1		sys_reg(3, 0, 12, 12, 1)
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index b86a0776c407..cac9d563d97d 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -874,6 +874,13 @@ static void __hyp_text __vgic_v3_read_hppir(struct kvm_vcpu *vcpu,
>  	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
>  }
>  
> +static void __hyp_text __vgic_v3_read_rpr(struct kvm_vcpu *vcpu,
> +					  u32 vmcr, int rt)
> +{
> +	u32 val = __vgic_v3_get_highest_active_priority();
> +	vcpu_set_reg(vcpu, rt, val);
> +}
> +
>  int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  {
>  	int rt;
> @@ -963,6 +970,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  	case SYS_ICC_DIR_EL1:
>  		fn = __vgic_v3_write_dir;
>  		break;
> +	case SYS_ICC_RPR_EL1:
> +		fn = __vgic_v3_read_rpr;
> +		break;
>  	default:
>  		return 0;
>  	}
> -- 
> 2.11.0
> 

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

* Re: [PATCH v2 22/25] KVM: arm64: vgic-v3: Add ICV_CTLR_EL1 handler
  2017-06-01 10:21   ` Marc Zyngier
@ 2017-06-06 13:23     ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:23 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On Thu, Jun 01, 2017 at 11:21:14AM +0100, Marc Zyngier wrote:
> Add a handler for reading/writing the guest's view of the ICV_CTLR_EL1
> register. only EOIMode and CBPR are of interest here, as all the other
> bits directly come from ICH_VTR_EL2 and are Read-Only.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Acked-by: Christoffer Dall <cdall@linaro.org>

> ---
>  virt/kvm/arm/hyp/vgic-v3-sr.c | 46 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 46 insertions(+)
> 
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index cac9d563d97d..3a5749e6c797 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -881,6 +881,46 @@ static void __hyp_text __vgic_v3_read_rpr(struct kvm_vcpu *vcpu,
>  	vcpu_set_reg(vcpu, rt, val);
>  }
>  
> +static void __hyp_text __vgic_v3_read_ctlr(struct kvm_vcpu *vcpu,
> +					   u32 vmcr, int rt)
> +{
> +	u32 vtr, val;
> +
> +	vtr = read_gicreg(ICH_VTR_EL2);
> +	/* PRIbits */
> +	val = ((vtr >> 29) & 7) << ICC_CTLR_EL1_PRI_BITS_SHIFT;
> +	/* IDbits */
> +	val |= ((vtr >> 23) & 7) << ICC_CTLR_EL1_ID_BITS_SHIFT;
> +	/* SEIS */
> +	val |= ((vtr >> 22) & 1) << ICC_CTLR_EL1_SEIS_SHIFT;
> +	/* A3V */
> +	val |= ((vtr >> 21) & 1) << ICC_CTLR_EL1_A3V_SHIFT;
> +	/* EOImode */
> +	val |= ((vmcr & ICH_VMCR_EOIM_MASK) >> ICH_VMCR_EOIM_SHIFT) << ICC_CTLR_EL1_EOImode_SHIFT;
> +	/* CBPR */
> +	val |= (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT;
> +
> +	vcpu_set_reg(vcpu, rt, val);
> +}
> +
> +static void __hyp_text __vgic_v3_write_ctlr(struct kvm_vcpu *vcpu,
> +					    u32 vmcr, int rt)
> +{
> +	u32 val = vcpu_get_reg(vcpu, rt);
> +
> +	if (val & ICC_CTLR_EL1_CBPR_MASK)
> +		vmcr |= ICH_VMCR_CBPR_MASK;
> +	else
> +		vmcr &= ~ICH_VMCR_CBPR_MASK;
> +
> +	if (val & ICC_CTLR_EL1_EOImode_MASK)
> +		vmcr |= ICH_VMCR_EOIM_MASK;
> +	else
> +		vmcr &= ~ICH_VMCR_EOIM_MASK;
> +
> +	write_gicreg(vmcr, ICH_VMCR_EL2);
> +}
> +
>  int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  {
>  	int rt;
> @@ -973,6 +1013,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  	case SYS_ICC_RPR_EL1:
>  		fn = __vgic_v3_read_rpr;
>  		break;
> +	case SYS_ICC_CTLR_EL1:
> +		if (is_read)
> +			fn = __vgic_v3_read_ctlr;
> +		else
> +			fn = __vgic_v3_write_ctlr;
> +		break;
>  	default:
>  		return 0;
>  	}
> -- 
> 2.11.0
> 

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

* [PATCH v2 22/25] KVM: arm64: vgic-v3: Add ICV_CTLR_EL1 handler
@ 2017-06-06 13:23     ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 01, 2017 at 11:21:14AM +0100, Marc Zyngier wrote:
> Add a handler for reading/writing the guest's view of the ICV_CTLR_EL1
> register. only EOIMode and CBPR are of interest here, as all the other
> bits directly come from ICH_VTR_EL2 and are Read-Only.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Acked-by: Christoffer Dall <cdall@linaro.org>

> ---
>  virt/kvm/arm/hyp/vgic-v3-sr.c | 46 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 46 insertions(+)
> 
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index cac9d563d97d..3a5749e6c797 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -881,6 +881,46 @@ static void __hyp_text __vgic_v3_read_rpr(struct kvm_vcpu *vcpu,
>  	vcpu_set_reg(vcpu, rt, val);
>  }
>  
> +static void __hyp_text __vgic_v3_read_ctlr(struct kvm_vcpu *vcpu,
> +					   u32 vmcr, int rt)
> +{
> +	u32 vtr, val;
> +
> +	vtr = read_gicreg(ICH_VTR_EL2);
> +	/* PRIbits */
> +	val = ((vtr >> 29) & 7) << ICC_CTLR_EL1_PRI_BITS_SHIFT;
> +	/* IDbits */
> +	val |= ((vtr >> 23) & 7) << ICC_CTLR_EL1_ID_BITS_SHIFT;
> +	/* SEIS */
> +	val |= ((vtr >> 22) & 1) << ICC_CTLR_EL1_SEIS_SHIFT;
> +	/* A3V */
> +	val |= ((vtr >> 21) & 1) << ICC_CTLR_EL1_A3V_SHIFT;
> +	/* EOImode */
> +	val |= ((vmcr & ICH_VMCR_EOIM_MASK) >> ICH_VMCR_EOIM_SHIFT) << ICC_CTLR_EL1_EOImode_SHIFT;
> +	/* CBPR */
> +	val |= (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT;
> +
> +	vcpu_set_reg(vcpu, rt, val);
> +}
> +
> +static void __hyp_text __vgic_v3_write_ctlr(struct kvm_vcpu *vcpu,
> +					    u32 vmcr, int rt)
> +{
> +	u32 val = vcpu_get_reg(vcpu, rt);
> +
> +	if (val & ICC_CTLR_EL1_CBPR_MASK)
> +		vmcr |= ICH_VMCR_CBPR_MASK;
> +	else
> +		vmcr &= ~ICH_VMCR_CBPR_MASK;
> +
> +	if (val & ICC_CTLR_EL1_EOImode_MASK)
> +		vmcr |= ICH_VMCR_EOIM_MASK;
> +	else
> +		vmcr &= ~ICH_VMCR_EOIM_MASK;
> +
> +	write_gicreg(vmcr, ICH_VMCR_EL2);
> +}
> +
>  int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  {
>  	int rt;
> @@ -973,6 +1013,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  	case SYS_ICC_RPR_EL1:
>  		fn = __vgic_v3_read_rpr;
>  		break;
> +	case SYS_ICC_CTLR_EL1:
> +		if (is_read)
> +			fn = __vgic_v3_read_ctlr;
> +		else
> +			fn = __vgic_v3_write_ctlr;
> +		break;
>  	default:
>  		return 0;
>  	}
> -- 
> 2.11.0
> 

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

* Re: [PATCH v2 23/25] KVM: arm64: vgic-v3: Add ICV_PMR_EL1 handler
  2017-06-01 10:21   ` Marc Zyngier
@ 2017-06-06 13:23     ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:23 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On Thu, Jun 01, 2017 at 11:21:15AM +0100, Marc Zyngier wrote:
> Add a handler for reading/writing the guest's view of the ICC_PMR_EL1
> register, which is located in the ICH_VMCR_EL2.VPMR field.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Acked-by: Christoffer Dall <cdall@linaro.org>

> ---
>  virt/kvm/arm/hyp/vgic-v3-sr.c | 27 +++++++++++++++++++++++++++
>  1 file changed, 27 insertions(+)
> 
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 3a5749e6c797..3c6b7d46754a 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -874,6 +874,27 @@ static void __hyp_text __vgic_v3_read_hppir(struct kvm_vcpu *vcpu,
>  	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
>  }
>  
> +static void __hyp_text __vgic_v3_read_pmr(struct kvm_vcpu *vcpu,
> +					  u32 vmcr, int rt)
> +{
> +	vmcr &= ICH_VMCR_PMR_MASK;
> +	vmcr >>= ICH_VMCR_PMR_SHIFT;
> +	vcpu_set_reg(vcpu, rt, vmcr);
> +}
> +
> +static void __hyp_text __vgic_v3_write_pmr(struct kvm_vcpu *vcpu,
> +					   u32 vmcr, int rt)
> +{
> +	u32 val = vcpu_get_reg(vcpu, rt);
> +
> +	val <<= ICH_VMCR_PMR_SHIFT;
> +	val &= ICH_VMCR_PMR_MASK;
> +	vmcr &= ~ICH_VMCR_PMR_MASK;
> +	vmcr |= val;
> +
> +	write_gicreg(vmcr, ICH_VMCR_EL2);
> +}
> +
>  static void __hyp_text __vgic_v3_read_rpr(struct kvm_vcpu *vcpu,
>  					  u32 vmcr, int rt)
>  {
> @@ -1019,6 +1040,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  		else
>  			fn = __vgic_v3_write_ctlr;
>  		break;
> +	case SYS_ICC_PMR_EL1:
> +		if (is_read)
> +			fn = __vgic_v3_read_pmr;
> +		else
> +			fn = __vgic_v3_write_pmr;
> +		break;
>  	default:
>  		return 0;
>  	}
> -- 
> 2.11.0
> 

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

* [PATCH v2 23/25] KVM: arm64: vgic-v3: Add ICV_PMR_EL1 handler
@ 2017-06-06 13:23     ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 01, 2017 at 11:21:15AM +0100, Marc Zyngier wrote:
> Add a handler for reading/writing the guest's view of the ICC_PMR_EL1
> register, which is located in the ICH_VMCR_EL2.VPMR field.
> 
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Acked-by: Christoffer Dall <cdall@linaro.org>

> ---
>  virt/kvm/arm/hyp/vgic-v3-sr.c | 27 +++++++++++++++++++++++++++
>  1 file changed, 27 insertions(+)
> 
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 3a5749e6c797..3c6b7d46754a 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -874,6 +874,27 @@ static void __hyp_text __vgic_v3_read_hppir(struct kvm_vcpu *vcpu,
>  	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
>  }
>  
> +static void __hyp_text __vgic_v3_read_pmr(struct kvm_vcpu *vcpu,
> +					  u32 vmcr, int rt)
> +{
> +	vmcr &= ICH_VMCR_PMR_MASK;
> +	vmcr >>= ICH_VMCR_PMR_SHIFT;
> +	vcpu_set_reg(vcpu, rt, vmcr);
> +}
> +
> +static void __hyp_text __vgic_v3_write_pmr(struct kvm_vcpu *vcpu,
> +					   u32 vmcr, int rt)
> +{
> +	u32 val = vcpu_get_reg(vcpu, rt);
> +
> +	val <<= ICH_VMCR_PMR_SHIFT;
> +	val &= ICH_VMCR_PMR_MASK;
> +	vmcr &= ~ICH_VMCR_PMR_MASK;
> +	vmcr |= val;
> +
> +	write_gicreg(vmcr, ICH_VMCR_EL2);
> +}
> +
>  static void __hyp_text __vgic_v3_read_rpr(struct kvm_vcpu *vcpu,
>  					  u32 vmcr, int rt)
>  {
> @@ -1019,6 +1040,12 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>  		else
>  			fn = __vgic_v3_write_ctlr;
>  		break;
> +	case SYS_ICC_PMR_EL1:
> +		if (is_read)
> +			fn = __vgic_v3_read_pmr;
> +		else
> +			fn = __vgic_v3_write_pmr;
> +		break;
>  	default:
>  		return 0;
>  	}
> -- 
> 2.11.0
> 

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

* Re: [PATCH v2 25/25] KVM: arm64: vgic-v3: Log which GICv3 system registers are trapped
  2017-06-01 10:21   ` Marc Zyngier
@ 2017-06-06 13:23     ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:23 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On Thu, Jun 01, 2017 at 11:21:17AM +0100, Marc Zyngier wrote:
> In order to facilitate debug, let's log which class of GICv3 system
> registers are trapped.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Acked-by: Christoffer Dall <cdall@linaro.org>

> ---
>  virt/kvm/arm/vgic/vgic-v3.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 636f1258d217..e0b530f4b1e6 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -499,7 +499,10 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
>  #endif
>  
>  	if (group0_trap || group1_trap || common_trap) {
> -		kvm_info("GICv3 sysreg trapping enabled (reduced performance)\n");
> +		kvm_info("GICv3 sysreg trapping enabled ([%s%s%s], reduced performance)\n",
> +			 group0_trap ? "G0" : "",
> +			 group1_trap ? "G1" : "",
> +			 common_trap ? "C"  : "");
>  		static_branch_enable(&vgic_v3_cpuif_trap);
>  	}
>  
> -- 
> 2.11.0
> 

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

* [PATCH v2 25/25] KVM: arm64: vgic-v3: Log which GICv3 system registers are trapped
@ 2017-06-06 13:23     ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 01, 2017 at 11:21:17AM +0100, Marc Zyngier wrote:
> In order to facilitate debug, let's log which class of GICv3 system
> registers are trapped.
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

Acked-by: Christoffer Dall <cdall@linaro.org>

> ---
>  virt/kvm/arm/vgic/vgic-v3.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 636f1258d217..e0b530f4b1e6 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -499,7 +499,10 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
>  #endif
>  
>  	if (group0_trap || group1_trap || common_trap) {
> -		kvm_info("GICv3 sysreg trapping enabled (reduced performance)\n");
> +		kvm_info("GICv3 sysreg trapping enabled ([%s%s%s], reduced performance)\n",
> +			 group0_trap ? "G0" : "",
> +			 group1_trap ? "G1" : "",
> +			 common_trap ? "C"  : "");
>  		static_branch_enable(&vgic_v3_cpuif_trap);
>  	}
>  
> -- 
> 2.11.0
> 

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

* Re: [PATCH v2 07/25] KVM: arm64: vgic-v3: Add ICV_IAR1_EL1 handler
  2017-06-06 11:09         ` Christoffer Dall
@ 2017-06-06 13:35           ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-06 13:35 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On 06/06/17 12:09, Christoffer Dall wrote:
> On Mon, Jun 05, 2017 at 11:33:52AM +0100, Marc Zyngier wrote:
>> On 05/06/17 10:21, Christoffer Dall wrote:
>>> On Thu, Jun 01, 2017 at 11:20:59AM +0100, Marc Zyngier wrote:
>>>> Add a handler for reading the guest's view of the ICC_IAR1_EL1
>>>> register. This involves finding the highest priority Group-1
>>>> interrupt, checking against both PMR and the active group
>>>> priority, activating the interrupt and setting the group
>>>> priority as active.
>>>>
>>>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>> ---
>>>>  include/linux/irqchip/arm-gic-v3.h |   1 +
>>>>  virt/kvm/arm/hyp/vgic-v3-sr.c      | 150 +++++++++++++++++++++++++++++++++++++
>>>>  2 files changed, 151 insertions(+)
>>>>
>>>> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
>>>> index fffb91202bc9..401db585a534 100644
>>>> --- a/include/linux/irqchip/arm-gic-v3.h
>>>> +++ b/include/linux/irqchip/arm-gic-v3.h
>>>> @@ -405,6 +405,7 @@
>>>>  #define ICH_LR_PHYS_ID_SHIFT		32
>>>>  #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
>>>>  #define ICH_LR_PRIORITY_SHIFT		48
>>>> +#define ICH_LR_PRIORITY_MASK		(0xffULL << ICH_LR_PRIORITY_SHIFT)
>>>>  
>>>>  /* These are for GICv2 emulation only */
>>>>  #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
>>>> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
>>>> index 168539dfd0b9..16a2eadc7a5c 100644
>>>> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
>>>> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
>>>> @@ -24,6 +24,7 @@
>>>>  
>>>>  #define vtr_to_max_lr_idx(v)		((v) & 0xf)
>>>>  #define vtr_to_nr_pre_bits(v)		(((u32)(v) >> 26) + 1)
>>>> +#define vtr_to_nr_apr_regs(v)		(1 << (vtr_to_nr_pre_bits(v) - 5))
>>>>  
>>>>  static u64 __hyp_text __gic_v3_get_lr(unsigned int lr)
>>>>  {
>>>> @@ -375,6 +376,79 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
>>>>  
>>>>  #ifdef CONFIG_ARM64
>>>>  
>>>> +static int __hyp_text __vgic_v3_get_group(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	u32 esr = kvm_vcpu_get_hsr(vcpu);
>>>> +	u8 crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT;
>>>> +
>>>> +	return crm != 8;
>>>> +}
>>>> +
>>>> +#define GICv3_IDLE_PRIORITY	0xff
>>>> +
>>>> +static int __hyp_text __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu,
>>>> +						    u32 vmcr,
>>>> +						    u64 *lr_val)
>>>> +{
>>>> +	unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
>>>> +	u8 priority = GICv3_IDLE_PRIORITY;
>>>> +	int i, lr = -1;
>>>> +
>>>> +	for (i = 0; i < used_lrs; i++) {
>>>> +		u64 val = __gic_v3_get_lr(i);
>>>> +		u8 lr_prio = (val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
>>>> +
>>>> +		/* Not pending in the state? */
>>>> +		if ((val & ICH_LR_STATE) != ICH_LR_PENDING_BIT)
>>>> +			continue;
>>>> +
>>>> +		/* Group-0 interrupt, but Group-0 disabled? */
>>>> +		if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG0_MASK))
>>>> +			continue;
>>>> +
>>>> +		/* Group-1 interrupt, but Group-1 disabled? */
>>>> +		if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG1_MASK))
>>>> +			continue;
>>>> +
>>>> +		/* Not the highest priority? */
>>>> +		if (lr_prio >= priority)
>>>> +			continue;
>>>> +
>>>> +		/* This is a candidate */
>>>> +		priority = lr_prio;
>>>> +		*lr_val = val;
>>>> +		lr = i;
>>>> +	}
>>>> +
>>>> +	if (lr == -1)
>>>> +		*lr_val = ICC_IAR1_EL1_SPURIOUS;
>>>> +
>>>> +	return lr;
>>>> +}
>>>> +
>>>> +static int __hyp_text __vgic_v3_get_highest_active_priority(void)
>>>> +{
>>>> +	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
>>>> +	u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
>>>> +	u32 hap = 0;
>>>> +	int i;
>>>> +
>>>> +	for (i = 0; i < nr_apr_regs; i++) {
>>>> +		u32 val;
>>>> +
>>>> +		val  = __vgic_v3_read_ap0rn(i);
>>>> +		val |= __vgic_v3_read_ap1rn(i);
>>>> +		if (!val) {
>>>> +			hap += 32;
>>>> +			continue;
>>>> +		}
>>>> +
>>>> +		return (hap + __ffs(val)) << (8 - nr_pre_bits);
>>>
>>> I don't understand this shift, and I think I asked about it before, so
>>> maybe if it's a reused concept we can use a static inline or at least
>>> provide a comment?
>>
>> I tried to explain it in my reply to your comment on patch #5. Can
>> definitely make that a helper. I think part of the confusion is that
>> this constant is used in a number of ways to express the conversion
>> between a preemption level and a priority.
>>
> 
> ok, I understand it now, but it's weird that we use 8 as a constant here
> (which applied to both group 0 and group 1) but 7 and 8, respecitvely,
> for the writes to the bpr0.

I made it slightly simpler to understand in my current series (hopefully).

> I understand that these two concepts are actually independent and
> loosely related, so maybe adding something like this would help:
> 
> 		/*
> 		 * The ICH_AP0Rn_EL2 and ICH_AP1Rn_EL2 registers contain
> 		 * the active priority levels for this VCPU for the
> 		 * maximum number of supported priority levels, and we
> 		 * return the full priority level only if the BPR is
> 		 * programmed to its minimum, otherwise we return a
> 		 * combination of the priority level and subpriority, as
> 		 * determined by the setting of the BPR, but without the
> 		 * full subpriority.
> 		 */
> 
> Maybe this is wrong and will just confuse people more?

It seems right to me, so I'll paste it in.

>>>> +	}
>>>> +
>>>> +	return GICv3_IDLE_PRIORITY;
>>>> +}
>>>> +
>>>>  static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
>>>>  {
>>>>  	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
>>>> @@ -395,6 +469,79 @@ static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
>>>>  	return bpr;
>>>>  }
>>>>  
>>>> +/*
>>>> + * Convert a priority to a preemption level, taking the relevant BPR
>>>> + * into account by zeroing the sub-priority bits.
>>>> + */
>>>> +static u8 __hyp_text __vgic_v3_pri_to_pre(u8 pri, u32 vmcr, int grp)
>>>> +{
>>>> +	unsigned int bpr;
>>>> +
>>>> +	if (!grp)
>>>> +		bpr = __vgic_v3_get_bpr0(vmcr) + 1;
>>>> +	else
>>>> +		bpr = __vgic_v3_get_bpr1(vmcr);
>>>> +
>>>> +	return pri & (GENMASK(7, 0) << bpr);
>>>> +}
>>>> +
>>>> +/*
>>>> + * The priority value is independent of any of the BPR values, so we
>>>> + * normalize it using nr_pre_bits. This guarantees that no matter what
>>>> + * the guest does with its BPR, we can always set/get the same value
>>>> + * of a priority.
>>>> + */
>>>> +static void __hyp_text __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp)
>>>> +{
>>>> +	u8 nr_pre_bits, pre, ap;
>>>> +	u32 val;
>>>> +	int apr;
>>>> +
>>>> +	nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
>>>> +	pre = __vgic_v3_pri_to_pre(pri, vmcr, grp);
>>>> +	ap = pre >> (8 - nr_pre_bits);
>>>
>>> Again here, I don't get this shift.
>>>
>>>> +	apr = ap / 32;
>>>> +
>>>> +	val = __vgic_v3_read_ap1rn(apr);
>>>> +	__vgic_v3_write_ap1rn(val | BIT(ap % 32), apr);
>>>
>>> How are we sure this is a group 1 interrupt here?
>>
>> That's a bug, as we should definitely check grp here. Thanks for
>> noticing it!
>>
> 
> Sure.  Also, the spec says "Writing to these registers with any value
> other than the last read value of the register (or 0x00000000 for a
> newly set up virtual machine) can result in UNPREDICTABLE behavior of
> the virtual interrupt prioritization system allowing either: ...".  Does
> that just translate to "You should know what you're doing", or could we
> be breaking something here?

This is basically a "don't mess with the HW". But in our case, we're mostly
using the registers as storage, and doing the heavy lifting in SW.

> 
>>>> +}
>>>> +
>>>> +static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>>>> +{
>>>> +	u64 lr_val;
>>>> +	u8 lr_prio, pmr;
>>>> +	int lr, grp;
>>>> +
>>>> +	grp = __vgic_v3_get_group(vcpu);
>>>> +
>>>> +	lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
>>>> +	if (lr < 0)
>>>> +		goto spurious;
>>>> +
>>>> +	if (grp != !!(lr_val & ICH_LR_GROUP))
>>>> +		goto spurious;
>>>> +
>>>> +	pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
>>>> +	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
>>>> +	if (pmr <= lr_prio)
>>>> +		goto spurious;
>>>> +
>>>> +	if (__vgic_v3_get_highest_active_priority() <= lr_prio)
>>>> +		goto spurious;
> 
> Based on what I wrote above, don't you need to consider the actual
> setting of the BPR here?
> 
> For example, if __vgic_v3_get_highest_active_priority() == 100.10 and
> lr_prio == 100.09  (BPR == 5 for a group 1 interrupt) then you'll
> compare 10010 <= 10009, you won't take the branch and you'll let the
> guest ack another interrupt at the same-and-already-active preemption
> level.
> 
> Or am I again misunderstandin how this whole thing works?

I think you're right. This should read:

diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 78e267637bbd..8f565983de08 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -604,7 +604,7 @@ static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int r
 	if (pmr <= lr_prio)
 		goto spurious;
 
-	if (__vgic_v3_get_highest_active_priority() <= lr_prio)
+	if (__vgic_v3_get_highest_active_priority() <= __vgic_v3_pri_to_pre(lr_prio, vmcr, grp))
 		goto spurious;
 
 	lr_val &= ~ICH_LR_STATE;

so that we actually compare the preemption levels.

> 
>>>> +
>>>> +	lr_val &= ~ICH_LR_STATE;
>>>> +	/* No active state for LPIs */
>>>> +	if ((lr_val & ICH_LR_VIRTUAL_ID_MASK) <= VGIC_MAX_SPI)
>>>> +		lr_val |= ICH_LR_ACTIVE_BIT;
>>>> +	__gic_v3_set_lr(lr_val, lr);
>>>> +	__vgic_v3_set_active_priority(lr_prio, vmcr, grp);
>>>> +	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
>>>> +	return;
>>>> +
>>>> +spurious:
>>>> +	vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS);
>>>> +}
>>>> +
>>>>  static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>>>>  {
>>>>  	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
>>>> @@ -459,6 +606,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>>>>  	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
>>>>  
>>>>  	switch (sysreg) {
>>>> +	case SYS_ICC_IAR1_EL1:
>>>> +		fn = __vgic_v3_read_iar;
>>>> +		break;
>>>
>>> So we don't provide a write-ignore function here because we rely on the
>>> hardware to always trap that at EL1 instead?
>>>
>>> I remember we discussed this before, but I don't remember if the
>>> conclusion was that this is 100% safe.
>>
>> A properly designed CPU would UNDEF at EL1. I'm happy to try and detect
>> broken failing implementations here, but I'm not sure of what to do, as
>> we're not in the best context to handle this. We could continue exiting
>> to EL1 and handle things there...
>>
> 
> I feel like we decided that other parts of KVM relies on this being
> implemented correctly, so maybe this is not the place to begin being
> overly cautious about things.
> 
> That said, having a path back to EL1 where we can print stuff and
> create warnings, may not be an entirely bad idea.

I'll look at adding something that takes care of it.

Thanks,

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

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

* [PATCH v2 07/25] KVM: arm64: vgic-v3: Add ICV_IAR1_EL1 handler
@ 2017-06-06 13:35           ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-06 13:35 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/06/17 12:09, Christoffer Dall wrote:
> On Mon, Jun 05, 2017 at 11:33:52AM +0100, Marc Zyngier wrote:
>> On 05/06/17 10:21, Christoffer Dall wrote:
>>> On Thu, Jun 01, 2017 at 11:20:59AM +0100, Marc Zyngier wrote:
>>>> Add a handler for reading the guest's view of the ICC_IAR1_EL1
>>>> register. This involves finding the highest priority Group-1
>>>> interrupt, checking against both PMR and the active group
>>>> priority, activating the interrupt and setting the group
>>>> priority as active.
>>>>
>>>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>>> ---
>>>>  include/linux/irqchip/arm-gic-v3.h |   1 +
>>>>  virt/kvm/arm/hyp/vgic-v3-sr.c      | 150 +++++++++++++++++++++++++++++++++++++
>>>>  2 files changed, 151 insertions(+)
>>>>
>>>> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
>>>> index fffb91202bc9..401db585a534 100644
>>>> --- a/include/linux/irqchip/arm-gic-v3.h
>>>> +++ b/include/linux/irqchip/arm-gic-v3.h
>>>> @@ -405,6 +405,7 @@
>>>>  #define ICH_LR_PHYS_ID_SHIFT		32
>>>>  #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
>>>>  #define ICH_LR_PRIORITY_SHIFT		48
>>>> +#define ICH_LR_PRIORITY_MASK		(0xffULL << ICH_LR_PRIORITY_SHIFT)
>>>>  
>>>>  /* These are for GICv2 emulation only */
>>>>  #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
>>>> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
>>>> index 168539dfd0b9..16a2eadc7a5c 100644
>>>> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
>>>> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
>>>> @@ -24,6 +24,7 @@
>>>>  
>>>>  #define vtr_to_max_lr_idx(v)		((v) & 0xf)
>>>>  #define vtr_to_nr_pre_bits(v)		(((u32)(v) >> 26) + 1)
>>>> +#define vtr_to_nr_apr_regs(v)		(1 << (vtr_to_nr_pre_bits(v) - 5))
>>>>  
>>>>  static u64 __hyp_text __gic_v3_get_lr(unsigned int lr)
>>>>  {
>>>> @@ -375,6 +376,79 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
>>>>  
>>>>  #ifdef CONFIG_ARM64
>>>>  
>>>> +static int __hyp_text __vgic_v3_get_group(struct kvm_vcpu *vcpu)
>>>> +{
>>>> +	u32 esr = kvm_vcpu_get_hsr(vcpu);
>>>> +	u8 crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT;
>>>> +
>>>> +	return crm != 8;
>>>> +}
>>>> +
>>>> +#define GICv3_IDLE_PRIORITY	0xff
>>>> +
>>>> +static int __hyp_text __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu,
>>>> +						    u32 vmcr,
>>>> +						    u64 *lr_val)
>>>> +{
>>>> +	unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
>>>> +	u8 priority = GICv3_IDLE_PRIORITY;
>>>> +	int i, lr = -1;
>>>> +
>>>> +	for (i = 0; i < used_lrs; i++) {
>>>> +		u64 val = __gic_v3_get_lr(i);
>>>> +		u8 lr_prio = (val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
>>>> +
>>>> +		/* Not pending in the state? */
>>>> +		if ((val & ICH_LR_STATE) != ICH_LR_PENDING_BIT)
>>>> +			continue;
>>>> +
>>>> +		/* Group-0 interrupt, but Group-0 disabled? */
>>>> +		if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG0_MASK))
>>>> +			continue;
>>>> +
>>>> +		/* Group-1 interrupt, but Group-1 disabled? */
>>>> +		if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG1_MASK))
>>>> +			continue;
>>>> +
>>>> +		/* Not the highest priority? */
>>>> +		if (lr_prio >= priority)
>>>> +			continue;
>>>> +
>>>> +		/* This is a candidate */
>>>> +		priority = lr_prio;
>>>> +		*lr_val = val;
>>>> +		lr = i;
>>>> +	}
>>>> +
>>>> +	if (lr == -1)
>>>> +		*lr_val = ICC_IAR1_EL1_SPURIOUS;
>>>> +
>>>> +	return lr;
>>>> +}
>>>> +
>>>> +static int __hyp_text __vgic_v3_get_highest_active_priority(void)
>>>> +{
>>>> +	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
>>>> +	u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
>>>> +	u32 hap = 0;
>>>> +	int i;
>>>> +
>>>> +	for (i = 0; i < nr_apr_regs; i++) {
>>>> +		u32 val;
>>>> +
>>>> +		val  = __vgic_v3_read_ap0rn(i);
>>>> +		val |= __vgic_v3_read_ap1rn(i);
>>>> +		if (!val) {
>>>> +			hap += 32;
>>>> +			continue;
>>>> +		}
>>>> +
>>>> +		return (hap + __ffs(val)) << (8 - nr_pre_bits);
>>>
>>> I don't understand this shift, and I think I asked about it before, so
>>> maybe if it's a reused concept we can use a static inline or at least
>>> provide a comment?
>>
>> I tried to explain it in my reply to your comment on patch #5. Can
>> definitely make that a helper. I think part of the confusion is that
>> this constant is used in a number of ways to express the conversion
>> between a preemption level and a priority.
>>
> 
> ok, I understand it now, but it's weird that we use 8 as a constant here
> (which applied to both group 0 and group 1) but 7 and 8, respecitvely,
> for the writes to the bpr0.

I made it slightly simpler to understand in my current series (hopefully).

> I understand that these two concepts are actually independent and
> loosely related, so maybe adding something like this would help:
> 
> 		/*
> 		 * The ICH_AP0Rn_EL2 and ICH_AP1Rn_EL2 registers contain
> 		 * the active priority levels for this VCPU for the
> 		 * maximum number of supported priority levels, and we
> 		 * return the full priority level only if the BPR is
> 		 * programmed to its minimum, otherwise we return a
> 		 * combination of the priority level and subpriority, as
> 		 * determined by the setting of the BPR, but without the
> 		 * full subpriority.
> 		 */
> 
> Maybe this is wrong and will just confuse people more?

It seems right to me, so I'll paste it in.

>>>> +	}
>>>> +
>>>> +	return GICv3_IDLE_PRIORITY;
>>>> +}
>>>> +
>>>>  static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
>>>>  {
>>>>  	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
>>>> @@ -395,6 +469,79 @@ static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
>>>>  	return bpr;
>>>>  }
>>>>  
>>>> +/*
>>>> + * Convert a priority to a preemption level, taking the relevant BPR
>>>> + * into account by zeroing the sub-priority bits.
>>>> + */
>>>> +static u8 __hyp_text __vgic_v3_pri_to_pre(u8 pri, u32 vmcr, int grp)
>>>> +{
>>>> +	unsigned int bpr;
>>>> +
>>>> +	if (!grp)
>>>> +		bpr = __vgic_v3_get_bpr0(vmcr) + 1;
>>>> +	else
>>>> +		bpr = __vgic_v3_get_bpr1(vmcr);
>>>> +
>>>> +	return pri & (GENMASK(7, 0) << bpr);
>>>> +}
>>>> +
>>>> +/*
>>>> + * The priority value is independent of any of the BPR values, so we
>>>> + * normalize it using nr_pre_bits. This guarantees that no matter what
>>>> + * the guest does with its BPR, we can always set/get the same value
>>>> + * of a priority.
>>>> + */
>>>> +static void __hyp_text __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp)
>>>> +{
>>>> +	u8 nr_pre_bits, pre, ap;
>>>> +	u32 val;
>>>> +	int apr;
>>>> +
>>>> +	nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
>>>> +	pre = __vgic_v3_pri_to_pre(pri, vmcr, grp);
>>>> +	ap = pre >> (8 - nr_pre_bits);
>>>
>>> Again here, I don't get this shift.
>>>
>>>> +	apr = ap / 32;
>>>> +
>>>> +	val = __vgic_v3_read_ap1rn(apr);
>>>> +	__vgic_v3_write_ap1rn(val | BIT(ap % 32), apr);
>>>
>>> How are we sure this is a group 1 interrupt here?
>>
>> That's a bug, as we should definitely check grp here. Thanks for
>> noticing it!
>>
> 
> Sure.  Also, the spec says "Writing to these registers with any value
> other than the last read value of the register (or 0x00000000 for a
> newly set up virtual machine) can result in UNPREDICTABLE behavior of
> the virtual interrupt prioritization system allowing either: ...".  Does
> that just translate to "You should know what you're doing", or could we
> be breaking something here?

This is basically a "don't mess with the HW". But in our case, we're mostly
using the registers as storage, and doing the heavy lifting in SW.

> 
>>>> +}
>>>> +
>>>> +static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>>>> +{
>>>> +	u64 lr_val;
>>>> +	u8 lr_prio, pmr;
>>>> +	int lr, grp;
>>>> +
>>>> +	grp = __vgic_v3_get_group(vcpu);
>>>> +
>>>> +	lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
>>>> +	if (lr < 0)
>>>> +		goto spurious;
>>>> +
>>>> +	if (grp != !!(lr_val & ICH_LR_GROUP))
>>>> +		goto spurious;
>>>> +
>>>> +	pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
>>>> +	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
>>>> +	if (pmr <= lr_prio)
>>>> +		goto spurious;
>>>> +
>>>> +	if (__vgic_v3_get_highest_active_priority() <= lr_prio)
>>>> +		goto spurious;
> 
> Based on what I wrote above, don't you need to consider the actual
> setting of the BPR here?
> 
> For example, if __vgic_v3_get_highest_active_priority() == 100.10 and
> lr_prio == 100.09  (BPR == 5 for a group 1 interrupt) then you'll
> compare 10010 <= 10009, you won't take the branch and you'll let the
> guest ack another interrupt at the same-and-already-active preemption
> level.
> 
> Or am I again misunderstandin how this whole thing works?

I think you're right. This should read:

diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 78e267637bbd..8f565983de08 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -604,7 +604,7 @@ static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int r
 	if (pmr <= lr_prio)
 		goto spurious;
 
-	if (__vgic_v3_get_highest_active_priority() <= lr_prio)
+	if (__vgic_v3_get_highest_active_priority() <= __vgic_v3_pri_to_pre(lr_prio, vmcr, grp))
 		goto spurious;
 
 	lr_val &= ~ICH_LR_STATE;

so that we actually compare the preemption levels.

> 
>>>> +
>>>> +	lr_val &= ~ICH_LR_STATE;
>>>> +	/* No active state for LPIs */
>>>> +	if ((lr_val & ICH_LR_VIRTUAL_ID_MASK) <= VGIC_MAX_SPI)
>>>> +		lr_val |= ICH_LR_ACTIVE_BIT;
>>>> +	__gic_v3_set_lr(lr_val, lr);
>>>> +	__vgic_v3_set_active_priority(lr_prio, vmcr, grp);
>>>> +	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
>>>> +	return;
>>>> +
>>>> +spurious:
>>>> +	vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS);
>>>> +}
>>>> +
>>>>  static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>>>>  {
>>>>  	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
>>>> @@ -459,6 +606,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
>>>>  	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
>>>>  
>>>>  	switch (sysreg) {
>>>> +	case SYS_ICC_IAR1_EL1:
>>>> +		fn = __vgic_v3_read_iar;
>>>> +		break;
>>>
>>> So we don't provide a write-ignore function here because we rely on the
>>> hardware to always trap that at EL1 instead?
>>>
>>> I remember we discussed this before, but I don't remember if the
>>> conclusion was that this is 100% safe.
>>
>> A properly designed CPU would UNDEF at EL1. I'm happy to try and detect
>> broken failing implementations here, but I'm not sure of what to do, as
>> we're not in the best context to handle this. We could continue exiting
>> to EL1 and handle things there...
>>
> 
> I feel like we decided that other parts of KVM relies on this being
> implemented correctly, so maybe this is not the place to begin being
> overly cautious about things.
> 
> That said, having a path back to EL1 where we can print stuff and
> create warnings, may not be an entirely bad idea.

I'll look at adding something that takes care of it.

Thanks,

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

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

* Re: [PATCH v2 07/25] KVM: arm64: vgic-v3: Add ICV_IAR1_EL1 handler
  2017-06-06 13:35           ` Marc Zyngier
@ 2017-06-06 13:50             ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:50 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter,
	linux-arm-kernel, kvmarm

On Tue, Jun 06, 2017 at 02:35:30PM +0100, Marc Zyngier wrote:
> On 06/06/17 12:09, Christoffer Dall wrote:
> > On Mon, Jun 05, 2017 at 11:33:52AM +0100, Marc Zyngier wrote:
> >> On 05/06/17 10:21, Christoffer Dall wrote:
> >>> On Thu, Jun 01, 2017 at 11:20:59AM +0100, Marc Zyngier wrote:
> >>>> Add a handler for reading the guest's view of the ICC_IAR1_EL1
> >>>> register. This involves finding the highest priority Group-1
> >>>> interrupt, checking against both PMR and the active group
> >>>> priority, activating the interrupt and setting the group
> >>>> priority as active.
> >>>>
> >>>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> >>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >>>> ---
> >>>>  include/linux/irqchip/arm-gic-v3.h |   1 +
> >>>>  virt/kvm/arm/hyp/vgic-v3-sr.c      | 150 +++++++++++++++++++++++++++++++++++++
> >>>>  2 files changed, 151 insertions(+)
> >>>>
> >>>> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> >>>> index fffb91202bc9..401db585a534 100644
> >>>> --- a/include/linux/irqchip/arm-gic-v3.h
> >>>> +++ b/include/linux/irqchip/arm-gic-v3.h
> >>>> @@ -405,6 +405,7 @@
> >>>>  #define ICH_LR_PHYS_ID_SHIFT		32
> >>>>  #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
> >>>>  #define ICH_LR_PRIORITY_SHIFT		48
> >>>> +#define ICH_LR_PRIORITY_MASK		(0xffULL << ICH_LR_PRIORITY_SHIFT)
> >>>>  
> >>>>  /* These are for GICv2 emulation only */
> >>>>  #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
> >>>> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >>>> index 168539dfd0b9..16a2eadc7a5c 100644
> >>>> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> >>>> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >>>> @@ -24,6 +24,7 @@
> >>>>  
> >>>>  #define vtr_to_max_lr_idx(v)		((v) & 0xf)
> >>>>  #define vtr_to_nr_pre_bits(v)		(((u32)(v) >> 26) + 1)
> >>>> +#define vtr_to_nr_apr_regs(v)		(1 << (vtr_to_nr_pre_bits(v) - 5))
> >>>>  
> >>>>  static u64 __hyp_text __gic_v3_get_lr(unsigned int lr)
> >>>>  {
> >>>> @@ -375,6 +376,79 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
> >>>>  
> >>>>  #ifdef CONFIG_ARM64
> >>>>  
> >>>> +static int __hyp_text __vgic_v3_get_group(struct kvm_vcpu *vcpu)
> >>>> +{
> >>>> +	u32 esr = kvm_vcpu_get_hsr(vcpu);
> >>>> +	u8 crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT;
> >>>> +
> >>>> +	return crm != 8;
> >>>> +}
> >>>> +
> >>>> +#define GICv3_IDLE_PRIORITY	0xff
> >>>> +
> >>>> +static int __hyp_text __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu,
> >>>> +						    u32 vmcr,
> >>>> +						    u64 *lr_val)
> >>>> +{
> >>>> +	unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
> >>>> +	u8 priority = GICv3_IDLE_PRIORITY;
> >>>> +	int i, lr = -1;
> >>>> +
> >>>> +	for (i = 0; i < used_lrs; i++) {
> >>>> +		u64 val = __gic_v3_get_lr(i);
> >>>> +		u8 lr_prio = (val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
> >>>> +
> >>>> +		/* Not pending in the state? */
> >>>> +		if ((val & ICH_LR_STATE) != ICH_LR_PENDING_BIT)
> >>>> +			continue;
> >>>> +
> >>>> +		/* Group-0 interrupt, but Group-0 disabled? */
> >>>> +		if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG0_MASK))
> >>>> +			continue;
> >>>> +
> >>>> +		/* Group-1 interrupt, but Group-1 disabled? */
> >>>> +		if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG1_MASK))
> >>>> +			continue;
> >>>> +
> >>>> +		/* Not the highest priority? */
> >>>> +		if (lr_prio >= priority)
> >>>> +			continue;
> >>>> +
> >>>> +		/* This is a candidate */
> >>>> +		priority = lr_prio;
> >>>> +		*lr_val = val;
> >>>> +		lr = i;
> >>>> +	}
> >>>> +
> >>>> +	if (lr == -1)
> >>>> +		*lr_val = ICC_IAR1_EL1_SPURIOUS;
> >>>> +
> >>>> +	return lr;
> >>>> +}
> >>>> +
> >>>> +static int __hyp_text __vgic_v3_get_highest_active_priority(void)
> >>>> +{
> >>>> +	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> >>>> +	u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
> >>>> +	u32 hap = 0;
> >>>> +	int i;
> >>>> +
> >>>> +	for (i = 0; i < nr_apr_regs; i++) {
> >>>> +		u32 val;
> >>>> +
> >>>> +		val  = __vgic_v3_read_ap0rn(i);
> >>>> +		val |= __vgic_v3_read_ap1rn(i);
> >>>> +		if (!val) {
> >>>> +			hap += 32;
> >>>> +			continue;
> >>>> +		}
> >>>> +
> >>>> +		return (hap + __ffs(val)) << (8 - nr_pre_bits);
> >>>
> >>> I don't understand this shift, and I think I asked about it before, so
> >>> maybe if it's a reused concept we can use a static inline or at least
> >>> provide a comment?
> >>
> >> I tried to explain it in my reply to your comment on patch #5. Can
> >> definitely make that a helper. I think part of the confusion is that
> >> this constant is used in a number of ways to express the conversion
> >> between a preemption level and a priority.
> >>
> > 
> > ok, I understand it now, but it's weird that we use 8 as a constant here
> > (which applied to both group 0 and group 1) but 7 and 8, respecitvely,
> > for the writes to the bpr0.
> 
> I made it slightly simpler to understand in my current series (hopefully).
> 
> > I understand that these two concepts are actually independent and
> > loosely related, so maybe adding something like this would help:
> > 
> > 		/*
> > 		 * The ICH_AP0Rn_EL2 and ICH_AP1Rn_EL2 registers contain
> > 		 * the active priority levels for this VCPU for the
> > 		 * maximum number of supported priority levels, and we
> > 		 * return the full priority level only if the BPR is
> > 		 * programmed to its minimum, otherwise we return a
> > 		 * combination of the priority level and subpriority, as
> > 		 * determined by the setting of the BPR, but without the
> > 		 * full subpriority.
> > 		 */
> > 
> > Maybe this is wrong and will just confuse people more?
> 
> It seems right to me, so I'll paste it in.
> 
> >>>> +	}
> >>>> +
> >>>> +	return GICv3_IDLE_PRIORITY;
> >>>> +}
> >>>> +
> >>>>  static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
> >>>>  {
> >>>>  	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
> >>>> @@ -395,6 +469,79 @@ static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
> >>>>  	return bpr;
> >>>>  }
> >>>>  
> >>>> +/*
> >>>> + * Convert a priority to a preemption level, taking the relevant BPR
> >>>> + * into account by zeroing the sub-priority bits.
> >>>> + */
> >>>> +static u8 __hyp_text __vgic_v3_pri_to_pre(u8 pri, u32 vmcr, int grp)
> >>>> +{
> >>>> +	unsigned int bpr;
> >>>> +
> >>>> +	if (!grp)
> >>>> +		bpr = __vgic_v3_get_bpr0(vmcr) + 1;
> >>>> +	else
> >>>> +		bpr = __vgic_v3_get_bpr1(vmcr);
> >>>> +
> >>>> +	return pri & (GENMASK(7, 0) << bpr);
> >>>> +}
> >>>> +
> >>>> +/*
> >>>> + * The priority value is independent of any of the BPR values, so we
> >>>> + * normalize it using nr_pre_bits. This guarantees that no matter what
> >>>> + * the guest does with its BPR, we can always set/get the same value
> >>>> + * of a priority.
> >>>> + */
> >>>> +static void __hyp_text __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp)
> >>>> +{
> >>>> +	u8 nr_pre_bits, pre, ap;
> >>>> +	u32 val;
> >>>> +	int apr;
> >>>> +
> >>>> +	nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> >>>> +	pre = __vgic_v3_pri_to_pre(pri, vmcr, grp);
> >>>> +	ap = pre >> (8 - nr_pre_bits);
> >>>
> >>> Again here, I don't get this shift.
> >>>
> >>>> +	apr = ap / 32;
> >>>> +
> >>>> +	val = __vgic_v3_read_ap1rn(apr);
> >>>> +	__vgic_v3_write_ap1rn(val | BIT(ap % 32), apr);
> >>>
> >>> How are we sure this is a group 1 interrupt here?
> >>
> >> That's a bug, as we should definitely check grp here. Thanks for
> >> noticing it!
> >>
> > 
> > Sure.  Also, the spec says "Writing to these registers with any value
> > other than the last read value of the register (or 0x00000000 for a
> > newly set up virtual machine) can result in UNPREDICTABLE behavior of
> > the virtual interrupt prioritization system allowing either: ...".  Does
> > that just translate to "You should know what you're doing", or could we
> > be breaking something here?
> 
> This is basically a "don't mess with the HW". But in our case, we're mostly
> using the registers as storage, and doing the heavy lifting in SW.
> 
> > 
> >>>> +}
> >>>> +
> >>>> +static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >>>> +{
> >>>> +	u64 lr_val;
> >>>> +	u8 lr_prio, pmr;
> >>>> +	int lr, grp;
> >>>> +
> >>>> +	grp = __vgic_v3_get_group(vcpu);
> >>>> +
> >>>> +	lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
> >>>> +	if (lr < 0)
> >>>> +		goto spurious;
> >>>> +
> >>>> +	if (grp != !!(lr_val & ICH_LR_GROUP))
> >>>> +		goto spurious;
> >>>> +
> >>>> +	pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
> >>>> +	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
> >>>> +	if (pmr <= lr_prio)
> >>>> +		goto spurious;
> >>>> +
> >>>> +	if (__vgic_v3_get_highest_active_priority() <= lr_prio)
> >>>> +		goto spurious;
> > 
> > Based on what I wrote above, don't you need to consider the actual
> > setting of the BPR here?
> > 
> > For example, if __vgic_v3_get_highest_active_priority() == 100.10 and
> > lr_prio == 100.09  (BPR == 5 for a group 1 interrupt) then you'll
> > compare 10010 <= 10009, you won't take the branch and you'll let the
> > guest ack another interrupt at the same-and-already-active preemption
> > level.
> > 
> > Or am I again misunderstandin how this whole thing works?
> 
> I think you're right. This should read:
> 
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 78e267637bbd..8f565983de08 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -604,7 +604,7 @@ static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int r
>  	if (pmr <= lr_prio)
>  		goto spurious;
>  
> -	if (__vgic_v3_get_highest_active_priority() <= lr_prio)
> +	if (__vgic_v3_get_highest_active_priority() <= __vgic_v3_pri_to_pre(lr_prio, vmcr, grp))
>  		goto spurious;
>  
>  	lr_val &= ~ICH_LR_STATE;
> 
> so that we actually compare the preemption levels.
> 

That looks good.

> > 
> >>>> +
> >>>> +	lr_val &= ~ICH_LR_STATE;
> >>>> +	/* No active state for LPIs */
> >>>> +	if ((lr_val & ICH_LR_VIRTUAL_ID_MASK) <= VGIC_MAX_SPI)
> >>>> +		lr_val |= ICH_LR_ACTIVE_BIT;
> >>>> +	__gic_v3_set_lr(lr_val, lr);
> >>>> +	__vgic_v3_set_active_priority(lr_prio, vmcr, grp);
> >>>> +	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
> >>>> +	return;
> >>>> +
> >>>> +spurious:
> >>>> +	vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS);
> >>>> +}
> >>>> +
> >>>>  static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >>>>  {
> >>>>  	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
> >>>> @@ -459,6 +606,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
> >>>>  	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
> >>>>  
> >>>>  	switch (sysreg) {
> >>>> +	case SYS_ICC_IAR1_EL1:
> >>>> +		fn = __vgic_v3_read_iar;
> >>>> +		break;
> >>>
> >>> So we don't provide a write-ignore function here because we rely on the
> >>> hardware to always trap that at EL1 instead?
> >>>
> >>> I remember we discussed this before, but I don't remember if the
> >>> conclusion was that this is 100% safe.
> >>
> >> A properly designed CPU would UNDEF at EL1. I'm happy to try and detect
> >> broken failing implementations here, but I'm not sure of what to do, as
> >> we're not in the best context to handle this. We could continue exiting
> >> to EL1 and handle things there...
> >>
> > 
> > I feel like we decided that other parts of KVM relies on this being
> > implemented correctly, so maybe this is not the place to begin being
> > overly cautious about things.
> > 
> > That said, having a path back to EL1 where we can print stuff and
> > create warnings, may not be an entirely bad idea.
> 
> I'll look at adding something that takes care of it.
> 

Thanks!
-Christoffer

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

* [PATCH v2 07/25] KVM: arm64: vgic-v3: Add ICV_IAR1_EL1 handler
@ 2017-06-06 13:50             ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 13:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jun 06, 2017 at 02:35:30PM +0100, Marc Zyngier wrote:
> On 06/06/17 12:09, Christoffer Dall wrote:
> > On Mon, Jun 05, 2017 at 11:33:52AM +0100, Marc Zyngier wrote:
> >> On 05/06/17 10:21, Christoffer Dall wrote:
> >>> On Thu, Jun 01, 2017 at 11:20:59AM +0100, Marc Zyngier wrote:
> >>>> Add a handler for reading the guest's view of the ICC_IAR1_EL1
> >>>> register. This involves finding the highest priority Group-1
> >>>> interrupt, checking against both PMR and the active group
> >>>> priority, activating the interrupt and setting the group
> >>>> priority as active.
> >>>>
> >>>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> >>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >>>> ---
> >>>>  include/linux/irqchip/arm-gic-v3.h |   1 +
> >>>>  virt/kvm/arm/hyp/vgic-v3-sr.c      | 150 +++++++++++++++++++++++++++++++++++++
> >>>>  2 files changed, 151 insertions(+)
> >>>>
> >>>> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> >>>> index fffb91202bc9..401db585a534 100644
> >>>> --- a/include/linux/irqchip/arm-gic-v3.h
> >>>> +++ b/include/linux/irqchip/arm-gic-v3.h
> >>>> @@ -405,6 +405,7 @@
> >>>>  #define ICH_LR_PHYS_ID_SHIFT		32
> >>>>  #define ICH_LR_PHYS_ID_MASK		(0x3ffULL << ICH_LR_PHYS_ID_SHIFT)
> >>>>  #define ICH_LR_PRIORITY_SHIFT		48
> >>>> +#define ICH_LR_PRIORITY_MASK		(0xffULL << ICH_LR_PRIORITY_SHIFT)
> >>>>  
> >>>>  /* These are for GICv2 emulation only */
> >>>>  #define GICH_LR_VIRTUALID		(0x3ffUL << 0)
> >>>> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >>>> index 168539dfd0b9..16a2eadc7a5c 100644
> >>>> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> >>>> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >>>> @@ -24,6 +24,7 @@
> >>>>  
> >>>>  #define vtr_to_max_lr_idx(v)		((v) & 0xf)
> >>>>  #define vtr_to_nr_pre_bits(v)		(((u32)(v) >> 26) + 1)
> >>>> +#define vtr_to_nr_apr_regs(v)		(1 << (vtr_to_nr_pre_bits(v) - 5))
> >>>>  
> >>>>  static u64 __hyp_text __gic_v3_get_lr(unsigned int lr)
> >>>>  {
> >>>> @@ -375,6 +376,79 @@ void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
> >>>>  
> >>>>  #ifdef CONFIG_ARM64
> >>>>  
> >>>> +static int __hyp_text __vgic_v3_get_group(struct kvm_vcpu *vcpu)
> >>>> +{
> >>>> +	u32 esr = kvm_vcpu_get_hsr(vcpu);
> >>>> +	u8 crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT;
> >>>> +
> >>>> +	return crm != 8;
> >>>> +}
> >>>> +
> >>>> +#define GICv3_IDLE_PRIORITY	0xff
> >>>> +
> >>>> +static int __hyp_text __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu,
> >>>> +						    u32 vmcr,
> >>>> +						    u64 *lr_val)
> >>>> +{
> >>>> +	unsigned int used_lrs = vcpu->arch.vgic_cpu.used_lrs;
> >>>> +	u8 priority = GICv3_IDLE_PRIORITY;
> >>>> +	int i, lr = -1;
> >>>> +
> >>>> +	for (i = 0; i < used_lrs; i++) {
> >>>> +		u64 val = __gic_v3_get_lr(i);
> >>>> +		u8 lr_prio = (val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
> >>>> +
> >>>> +		/* Not pending in the state? */
> >>>> +		if ((val & ICH_LR_STATE) != ICH_LR_PENDING_BIT)
> >>>> +			continue;
> >>>> +
> >>>> +		/* Group-0 interrupt, but Group-0 disabled? */
> >>>> +		if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG0_MASK))
> >>>> +			continue;
> >>>> +
> >>>> +		/* Group-1 interrupt, but Group-1 disabled? */
> >>>> +		if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG1_MASK))
> >>>> +			continue;
> >>>> +
> >>>> +		/* Not the highest priority? */
> >>>> +		if (lr_prio >= priority)
> >>>> +			continue;
> >>>> +
> >>>> +		/* This is a candidate */
> >>>> +		priority = lr_prio;
> >>>> +		*lr_val = val;
> >>>> +		lr = i;
> >>>> +	}
> >>>> +
> >>>> +	if (lr == -1)
> >>>> +		*lr_val = ICC_IAR1_EL1_SPURIOUS;
> >>>> +
> >>>> +	return lr;
> >>>> +}
> >>>> +
> >>>> +static int __hyp_text __vgic_v3_get_highest_active_priority(void)
> >>>> +{
> >>>> +	u8 nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> >>>> +	u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2));
> >>>> +	u32 hap = 0;
> >>>> +	int i;
> >>>> +
> >>>> +	for (i = 0; i < nr_apr_regs; i++) {
> >>>> +		u32 val;
> >>>> +
> >>>> +		val  = __vgic_v3_read_ap0rn(i);
> >>>> +		val |= __vgic_v3_read_ap1rn(i);
> >>>> +		if (!val) {
> >>>> +			hap += 32;
> >>>> +			continue;
> >>>> +		}
> >>>> +
> >>>> +		return (hap + __ffs(val)) << (8 - nr_pre_bits);
> >>>
> >>> I don't understand this shift, and I think I asked about it before, so
> >>> maybe if it's a reused concept we can use a static inline or at least
> >>> provide a comment?
> >>
> >> I tried to explain it in my reply to your comment on patch #5. Can
> >> definitely make that a helper. I think part of the confusion is that
> >> this constant is used in a number of ways to express the conversion
> >> between a preemption level and a priority.
> >>
> > 
> > ok, I understand it now, but it's weird that we use 8 as a constant here
> > (which applied to both group 0 and group 1) but 7 and 8, respecitvely,
> > for the writes to the bpr0.
> 
> I made it slightly simpler to understand in my current series (hopefully).
> 
> > I understand that these two concepts are actually independent and
> > loosely related, so maybe adding something like this would help:
> > 
> > 		/*
> > 		 * The ICH_AP0Rn_EL2 and ICH_AP1Rn_EL2 registers contain
> > 		 * the active priority levels for this VCPU for the
> > 		 * maximum number of supported priority levels, and we
> > 		 * return the full priority level only if the BPR is
> > 		 * programmed to its minimum, otherwise we return a
> > 		 * combination of the priority level and subpriority, as
> > 		 * determined by the setting of the BPR, but without the
> > 		 * full subpriority.
> > 		 */
> > 
> > Maybe this is wrong and will just confuse people more?
> 
> It seems right to me, so I'll paste it in.
> 
> >>>> +	}
> >>>> +
> >>>> +	return GICv3_IDLE_PRIORITY;
> >>>> +}
> >>>> +
> >>>>  static unsigned int __hyp_text __vgic_v3_get_bpr0(u32 vmcr)
> >>>>  {
> >>>>  	return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT;
> >>>> @@ -395,6 +469,79 @@ static unsigned int __hyp_text __vgic_v3_get_bpr1(u32 vmcr)
> >>>>  	return bpr;
> >>>>  }
> >>>>  
> >>>> +/*
> >>>> + * Convert a priority to a preemption level, taking the relevant BPR
> >>>> + * into account by zeroing the sub-priority bits.
> >>>> + */
> >>>> +static u8 __hyp_text __vgic_v3_pri_to_pre(u8 pri, u32 vmcr, int grp)
> >>>> +{
> >>>> +	unsigned int bpr;
> >>>> +
> >>>> +	if (!grp)
> >>>> +		bpr = __vgic_v3_get_bpr0(vmcr) + 1;
> >>>> +	else
> >>>> +		bpr = __vgic_v3_get_bpr1(vmcr);
> >>>> +
> >>>> +	return pri & (GENMASK(7, 0) << bpr);
> >>>> +}
> >>>> +
> >>>> +/*
> >>>> + * The priority value is independent of any of the BPR values, so we
> >>>> + * normalize it using nr_pre_bits. This guarantees that no matter what
> >>>> + * the guest does with its BPR, we can always set/get the same value
> >>>> + * of a priority.
> >>>> + */
> >>>> +static void __hyp_text __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp)
> >>>> +{
> >>>> +	u8 nr_pre_bits, pre, ap;
> >>>> +	u32 val;
> >>>> +	int apr;
> >>>> +
> >>>> +	nr_pre_bits = vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> >>>> +	pre = __vgic_v3_pri_to_pre(pri, vmcr, grp);
> >>>> +	ap = pre >> (8 - nr_pre_bits);
> >>>
> >>> Again here, I don't get this shift.
> >>>
> >>>> +	apr = ap / 32;
> >>>> +
> >>>> +	val = __vgic_v3_read_ap1rn(apr);
> >>>> +	__vgic_v3_write_ap1rn(val | BIT(ap % 32), apr);
> >>>
> >>> How are we sure this is a group 1 interrupt here?
> >>
> >> That's a bug, as we should definitely check grp here. Thanks for
> >> noticing it!
> >>
> > 
> > Sure.  Also, the spec says "Writing to these registers with any value
> > other than the last read value of the register (or 0x00000000 for a
> > newly set up virtual machine) can result in UNPREDICTABLE behavior of
> > the virtual interrupt prioritization system allowing either: ...".  Does
> > that just translate to "You should know what you're doing", or could we
> > be breaking something here?
> 
> This is basically a "don't mess with the HW". But in our case, we're mostly
> using the registers as storage, and doing the heavy lifting in SW.
> 
> > 
> >>>> +}
> >>>> +
> >>>> +static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >>>> +{
> >>>> +	u64 lr_val;
> >>>> +	u8 lr_prio, pmr;
> >>>> +	int lr, grp;
> >>>> +
> >>>> +	grp = __vgic_v3_get_group(vcpu);
> >>>> +
> >>>> +	lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
> >>>> +	if (lr < 0)
> >>>> +		goto spurious;
> >>>> +
> >>>> +	if (grp != !!(lr_val & ICH_LR_GROUP))
> >>>> +		goto spurious;
> >>>> +
> >>>> +	pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT;
> >>>> +	lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT;
> >>>> +	if (pmr <= lr_prio)
> >>>> +		goto spurious;
> >>>> +
> >>>> +	if (__vgic_v3_get_highest_active_priority() <= lr_prio)
> >>>> +		goto spurious;
> > 
> > Based on what I wrote above, don't you need to consider the actual
> > setting of the BPR here?
> > 
> > For example, if __vgic_v3_get_highest_active_priority() == 100.10 and
> > lr_prio == 100.09  (BPR == 5 for a group 1 interrupt) then you'll
> > compare 10010 <= 10009, you won't take the branch and you'll let the
> > guest ack another interrupt at the same-and-already-active preemption
> > level.
> > 
> > Or am I again misunderstandin how this whole thing works?
> 
> I think you're right. This should read:
> 
> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> index 78e267637bbd..8f565983de08 100644
> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> @@ -604,7 +604,7 @@ static void __hyp_text __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int r
>  	if (pmr <= lr_prio)
>  		goto spurious;
>  
> -	if (__vgic_v3_get_highest_active_priority() <= lr_prio)
> +	if (__vgic_v3_get_highest_active_priority() <= __vgic_v3_pri_to_pre(lr_prio, vmcr, grp))
>  		goto spurious;
>  
>  	lr_val &= ~ICH_LR_STATE;
> 
> so that we actually compare the preemption levels.
> 

That looks good.

> > 
> >>>> +
> >>>> +	lr_val &= ~ICH_LR_STATE;
> >>>> +	/* No active state for LPIs */
> >>>> +	if ((lr_val & ICH_LR_VIRTUAL_ID_MASK) <= VGIC_MAX_SPI)
> >>>> +		lr_val |= ICH_LR_ACTIVE_BIT;
> >>>> +	__gic_v3_set_lr(lr_val, lr);
> >>>> +	__vgic_v3_set_active_priority(lr_prio, vmcr, grp);
> >>>> +	vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK);
> >>>> +	return;
> >>>> +
> >>>> +spurious:
> >>>> +	vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS);
> >>>> +}
> >>>> +
> >>>>  static void __hyp_text __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >>>>  {
> >>>>  	vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK));
> >>>> @@ -459,6 +606,9 @@ int __hyp_text __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
> >>>>  	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;
> >>>>  
> >>>>  	switch (sysreg) {
> >>>> +	case SYS_ICC_IAR1_EL1:
> >>>> +		fn = __vgic_v3_read_iar;
> >>>> +		break;
> >>>
> >>> So we don't provide a write-ignore function here because we rely on the
> >>> hardware to always trap that at EL1 instead?
> >>>
> >>> I remember we discussed this before, but I don't remember if the
> >>> conclusion was that this is 100% safe.
> >>
> >> A properly designed CPU would UNDEF at EL1. I'm happy to try and detect
> >> broken failing implementations here, but I'm not sure of what to do, as
> >> we're not in the best context to handle this. We could continue exiting
> >> to EL1 and handle things there...
> >>
> > 
> > I feel like we decided that other parts of KVM relies on this being
> > implemented correctly, so maybe this is not the place to begin being
> > overly cautious about things.
> > 
> > That said, having a path back to EL1 where we can print stuff and
> > create warnings, may not be an entirely bad idea.
> 
> I'll look at adding something that takes care of it.
> 

Thanks!
-Christoffer

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

* Re: [PATCH v2 10/25] KVM: arm64: vgic-v3: Add ICV_HPPIR1_EL1 handler
  2017-06-06 11:51     ` Christoffer Dall
@ 2017-06-06 13:57       ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-06 13:57 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On 06/06/17 12:51, Christoffer Dall wrote:
> On Thu, Jun 01, 2017 at 11:21:02AM +0100, Marc Zyngier wrote:
>> Add a handler for reading the guest's view of the ICV_HPPIR1_EL1
>> register. This is a simple parsing of the available LRs, extracting the
>> highest available interrupt.
>>
>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  arch/arm64/include/asm/sysreg.h |  1 +
>>  virt/kvm/arm/hyp/vgic-v3-sr.c   | 23 +++++++++++++++++++++++
>>  2 files changed, 24 insertions(+)
>>
>> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
>> index aad46b8eea5e..bd000686194a 100644
>> --- a/arch/arm64/include/asm/sysreg.h
>> +++ b/arch/arm64/include/asm/sysreg.h
>> @@ -185,6 +185,7 @@
>>  #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
>>  #define SYS_ICC_IAR1_EL1		sys_reg(3, 0, 12, 12, 0)
>>  #define SYS_ICC_EOIR1_EL1		sys_reg(3, 0, 12, 12, 1)
>> +#define SYS_ICC_HPPIR1_EL1		sys_reg(3, 0, 12, 12, 2)
>>  #define SYS_ICC_BPR1_EL1		sys_reg(3, 0, 12, 12, 3)
>>  #define SYS_ICC_CTLR_EL1		sys_reg(3, 0, 12, 12, 4)
>>  #define SYS_ICC_SRE_EL1			sys_reg(3, 0, 12, 12, 5)
>> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> index d4f07f84602d..f0bc711db258 100644
>> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
>> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> @@ -772,6 +772,26 @@ static void __hyp_text __vgic_v3_write_apxr3(struct kvm_vcpu *vcpu,
>>  	__vgic_v3_write_apxrn(vcpu, rt, 3);
>>  }
>>  
>> +static void __hyp_text __vgic_v3_read_hppir(struct kvm_vcpu *vcpu,
>> +					    u32 vmcr, int rt)
>> +{
>> +	u64 lr_val;
>> +	int lr, lr_grp, grp;
>> +
>> +	grp = __vgic_v3_get_group(vcpu);
>> +
>> +	lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
>> +	if (lr == -1)
>> +		goto spurious;
>> +
>> +	lr_grp = !!(lr_val & ICH_LR_GROUP);
>> +	if (lr_grp != grp)
>> +		lr_val = ICC_IAR1_EL1_SPURIOUS;
> 
> I don't get this.  The spec says that the special INTID 1023
>   "...is returned in response to an interrupt acknowledge, if there is
>    no pending interrupt with sufficient priority for it to be signaled to
>    the PE, or if the highest priority pending interrupt is not
>    appropriate for the:
>     * Current Security state.  Interrupt group that is associated with
>     * the System register."
> 
> So do we just take this to imply that it also covers the HPPIRx_EL1
> registers (despite them being mentioned explicitly for the other special
> INTIDs) or is there some other piece of spec I'm missing here?

Here's what the ICV_HPPIRx_EL1 INTID description says:

"If the highest priority pending interrupt is not observable, this field
contains a special INTID to indicate the reason. This special INTID can
take the value 1023 only."

Yes, the disparity between ICC_HPPIRx_EL1 and ICV_HPPIRx_EL1 is very
confusing and makes me want to shout at people.

Thanks,

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

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

* [PATCH v2 10/25] KVM: arm64: vgic-v3: Add ICV_HPPIR1_EL1 handler
@ 2017-06-06 13:57       ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-06 13:57 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/06/17 12:51, Christoffer Dall wrote:
> On Thu, Jun 01, 2017 at 11:21:02AM +0100, Marc Zyngier wrote:
>> Add a handler for reading the guest's view of the ICV_HPPIR1_EL1
>> register. This is a simple parsing of the available LRs, extracting the
>> highest available interrupt.
>>
>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  arch/arm64/include/asm/sysreg.h |  1 +
>>  virt/kvm/arm/hyp/vgic-v3-sr.c   | 23 +++++++++++++++++++++++
>>  2 files changed, 24 insertions(+)
>>
>> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
>> index aad46b8eea5e..bd000686194a 100644
>> --- a/arch/arm64/include/asm/sysreg.h
>> +++ b/arch/arm64/include/asm/sysreg.h
>> @@ -185,6 +185,7 @@
>>  #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
>>  #define SYS_ICC_IAR1_EL1		sys_reg(3, 0, 12, 12, 0)
>>  #define SYS_ICC_EOIR1_EL1		sys_reg(3, 0, 12, 12, 1)
>> +#define SYS_ICC_HPPIR1_EL1		sys_reg(3, 0, 12, 12, 2)
>>  #define SYS_ICC_BPR1_EL1		sys_reg(3, 0, 12, 12, 3)
>>  #define SYS_ICC_CTLR_EL1		sys_reg(3, 0, 12, 12, 4)
>>  #define SYS_ICC_SRE_EL1			sys_reg(3, 0, 12, 12, 5)
>> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> index d4f07f84602d..f0bc711db258 100644
>> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
>> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> @@ -772,6 +772,26 @@ static void __hyp_text __vgic_v3_write_apxr3(struct kvm_vcpu *vcpu,
>>  	__vgic_v3_write_apxrn(vcpu, rt, 3);
>>  }
>>  
>> +static void __hyp_text __vgic_v3_read_hppir(struct kvm_vcpu *vcpu,
>> +					    u32 vmcr, int rt)
>> +{
>> +	u64 lr_val;
>> +	int lr, lr_grp, grp;
>> +
>> +	grp = __vgic_v3_get_group(vcpu);
>> +
>> +	lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
>> +	if (lr == -1)
>> +		goto spurious;
>> +
>> +	lr_grp = !!(lr_val & ICH_LR_GROUP);
>> +	if (lr_grp != grp)
>> +		lr_val = ICC_IAR1_EL1_SPURIOUS;
> 
> I don't get this.  The spec says that the special INTID 1023
>   "...is returned in response to an interrupt acknowledge, if there is
>    no pending interrupt with sufficient priority for it to be signaled to
>    the PE, or if the highest priority pending interrupt is not
>    appropriate for the:
>     * Current Security state.  Interrupt group that is associated with
>     * the System register."
> 
> So do we just take this to imply that it also covers the HPPIRx_EL1
> registers (despite them being mentioned explicitly for the other special
> INTIDs) or is there some other piece of spec I'm missing here?

Here's what the ICV_HPPIRx_EL1 INTID description says:

"If the highest priority pending interrupt is not observable, this field
contains a special INTID to indicate the reason. This special INTID can
take the value 1023 only."

Yes, the disparity between ICC_HPPIRx_EL1 and ICV_HPPIRx_EL1 is very
confusing and makes me want to shout at people.

Thanks,

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

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

* Re: [PATCH v2 12/25] KVM: arm64: Enable GICv3 Group-1 sysreg trapping via command-line
  2017-06-06 12:06     ` Christoffer Dall
@ 2017-06-06 13:59       ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-06 13:59 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On 06/06/17 13:06, Christoffer Dall wrote:
> On Thu, Jun 01, 2017 at 11:21:04AM +0100, Marc Zyngier wrote:
>> Now that we're able to safely handle Group-1 sysreg access, let's
>> give the user the opportunity to enable it by passing a specific
>> command-line option (vgic_v3.group1_trap).
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  virt/kvm/arm/hyp/vgic-v3-sr.c |  6 +++++-
>>  virt/kvm/arm/vgic/vgic-v3.c   | 11 +++++++++++
>>  2 files changed, 16 insertions(+), 1 deletion(-)
>>
>> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> index 8973bad35748..42ac9ee7650a 100644
>> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
>> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> @@ -334,7 +334,11 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
>>  		for (i = 0; i < used_lrs; i++)
>>  			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
>>  	} else {
>> -		/* Always write ICH_HCR_EL2 to enable trapping */
>> +		/*
>> +                 * If we don't have any interrupt to inject, but that
>> +		 * trapping is enabled, write the ICH_HCR_EL2 config
>> +		 * anyway.
>> +		 */
> 
> nit: Whitespace and grammar issues, and maybe this hunk was supposed to
> be in the last patch?

Indeed, on both counts.

> 
>>  		if (static_branch_unlikely(&vgic_v3_cpuif_trap))
>>  			write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
>>  	}
>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>> index fbd678bc046d..a16769276efd 100644
>> --- a/virt/kvm/arm/vgic/vgic-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>> @@ -416,6 +416,12 @@ int vgic_v3_map_resources(struct kvm *kvm)
>>  
>>  DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap);
>>  
>> +static int __init early_group1_trap_cfg(char *buf)
>> +{
>> +	return strtobool(buf, &group1_trap);
>> +}
>> +early_param("vgic_v3.group1_trap", early_group1_trap_cfg);
>> +
> 
> this shouldn't be named something with KVM (we're not going to trap
> anything on the host somehow are we?)?

Good point. kvm_vgic_v3.whatever?

Thanks,

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

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

* [PATCH v2 12/25] KVM: arm64: Enable GICv3 Group-1 sysreg trapping via command-line
@ 2017-06-06 13:59       ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-06 13:59 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/06/17 13:06, Christoffer Dall wrote:
> On Thu, Jun 01, 2017 at 11:21:04AM +0100, Marc Zyngier wrote:
>> Now that we're able to safely handle Group-1 sysreg access, let's
>> give the user the opportunity to enable it by passing a specific
>> command-line option (vgic_v3.group1_trap).
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  virt/kvm/arm/hyp/vgic-v3-sr.c |  6 +++++-
>>  virt/kvm/arm/vgic/vgic-v3.c   | 11 +++++++++++
>>  2 files changed, 16 insertions(+), 1 deletion(-)
>>
>> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> index 8973bad35748..42ac9ee7650a 100644
>> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
>> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> @@ -334,7 +334,11 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
>>  		for (i = 0; i < used_lrs; i++)
>>  			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
>>  	} else {
>> -		/* Always write ICH_HCR_EL2 to enable trapping */
>> +		/*
>> +                 * If we don't have any interrupt to inject, but that
>> +		 * trapping is enabled, write the ICH_HCR_EL2 config
>> +		 * anyway.
>> +		 */
> 
> nit: Whitespace and grammar issues, and maybe this hunk was supposed to
> be in the last patch?

Indeed, on both counts.

> 
>>  		if (static_branch_unlikely(&vgic_v3_cpuif_trap))
>>  			write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
>>  	}
>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>> index fbd678bc046d..a16769276efd 100644
>> --- a/virt/kvm/arm/vgic/vgic-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>> @@ -416,6 +416,12 @@ int vgic_v3_map_resources(struct kvm *kvm)
>>  
>>  DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap);
>>  
>> +static int __init early_group1_trap_cfg(char *buf)
>> +{
>> +	return strtobool(buf, &group1_trap);
>> +}
>> +early_param("vgic_v3.group1_trap", early_group1_trap_cfg);
>> +
> 
> this shouldn't be named something with KVM (we're not going to trap
> anything on the host somehow are we?)?

Good point. kvm_vgic_v3.whatever?

Thanks,

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

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

* Re: [PATCH v2 10/25] KVM: arm64: vgic-v3: Add ICV_HPPIR1_EL1 handler
  2017-06-06 13:57       ` Marc Zyngier
@ 2017-06-06 14:41         ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 14:41 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On Tue, Jun 06, 2017 at 02:57:42PM +0100, Marc Zyngier wrote:
> On 06/06/17 12:51, Christoffer Dall wrote:
> > On Thu, Jun 01, 2017 at 11:21:02AM +0100, Marc Zyngier wrote:
> >> Add a handler for reading the guest's view of the ICV_HPPIR1_EL1
> >> register. This is a simple parsing of the available LRs, extracting the
> >> highest available interrupt.
> >>
> >> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> ---
> >>  arch/arm64/include/asm/sysreg.h |  1 +
> >>  virt/kvm/arm/hyp/vgic-v3-sr.c   | 23 +++++++++++++++++++++++
> >>  2 files changed, 24 insertions(+)
> >>
> >> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> >> index aad46b8eea5e..bd000686194a 100644
> >> --- a/arch/arm64/include/asm/sysreg.h
> >> +++ b/arch/arm64/include/asm/sysreg.h
> >> @@ -185,6 +185,7 @@
> >>  #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
> >>  #define SYS_ICC_IAR1_EL1		sys_reg(3, 0, 12, 12, 0)
> >>  #define SYS_ICC_EOIR1_EL1		sys_reg(3, 0, 12, 12, 1)
> >> +#define SYS_ICC_HPPIR1_EL1		sys_reg(3, 0, 12, 12, 2)
> >>  #define SYS_ICC_BPR1_EL1		sys_reg(3, 0, 12, 12, 3)
> >>  #define SYS_ICC_CTLR_EL1		sys_reg(3, 0, 12, 12, 4)
> >>  #define SYS_ICC_SRE_EL1			sys_reg(3, 0, 12, 12, 5)
> >> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> index d4f07f84602d..f0bc711db258 100644
> >> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> @@ -772,6 +772,26 @@ static void __hyp_text __vgic_v3_write_apxr3(struct kvm_vcpu *vcpu,
> >>  	__vgic_v3_write_apxrn(vcpu, rt, 3);
> >>  }
> >>  
> >> +static void __hyp_text __vgic_v3_read_hppir(struct kvm_vcpu *vcpu,
> >> +					    u32 vmcr, int rt)
> >> +{
> >> +	u64 lr_val;
> >> +	int lr, lr_grp, grp;
> >> +
> >> +	grp = __vgic_v3_get_group(vcpu);
> >> +
> >> +	lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
> >> +	if (lr == -1)
> >> +		goto spurious;
> >> +
> >> +	lr_grp = !!(lr_val & ICH_LR_GROUP);
> >> +	if (lr_grp != grp)
> >> +		lr_val = ICC_IAR1_EL1_SPURIOUS;
> > 
> > I don't get this.  The spec says that the special INTID 1023
> >   "...is returned in response to an interrupt acknowledge, if there is
> >    no pending interrupt with sufficient priority for it to be signaled to
> >    the PE, or if the highest priority pending interrupt is not
> >    appropriate for the:
> >     * Current Security state.  Interrupt group that is associated with
> >     * the System register."
> > 
> > So do we just take this to imply that it also covers the HPPIRx_EL1
> > registers (despite them being mentioned explicitly for the other special
> > INTIDs) or is there some other piece of spec I'm missing here?
> 
> Here's what the ICV_HPPIRx_EL1 INTID description says:
> 
> "If the highest priority pending interrupt is not observable, this field
> contains a special INTID to indicate the reason. This special INTID can
> take the value 1023 only."
> 
> Yes, the disparity between ICC_HPPIRx_EL1 and ICV_HPPIRx_EL1 is very
> confusing and makes me want to shout at people.
> 

ok, shitty spec.

Thanks,
-Christoffer

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

* [PATCH v2 10/25] KVM: arm64: vgic-v3: Add ICV_HPPIR1_EL1 handler
@ 2017-06-06 14:41         ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 14:41 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jun 06, 2017 at 02:57:42PM +0100, Marc Zyngier wrote:
> On 06/06/17 12:51, Christoffer Dall wrote:
> > On Thu, Jun 01, 2017 at 11:21:02AM +0100, Marc Zyngier wrote:
> >> Add a handler for reading the guest's view of the ICV_HPPIR1_EL1
> >> register. This is a simple parsing of the available LRs, extracting the
> >> highest available interrupt.
> >>
> >> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> ---
> >>  arch/arm64/include/asm/sysreg.h |  1 +
> >>  virt/kvm/arm/hyp/vgic-v3-sr.c   | 23 +++++++++++++++++++++++
> >>  2 files changed, 24 insertions(+)
> >>
> >> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> >> index aad46b8eea5e..bd000686194a 100644
> >> --- a/arch/arm64/include/asm/sysreg.h
> >> +++ b/arch/arm64/include/asm/sysreg.h
> >> @@ -185,6 +185,7 @@
> >>  #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
> >>  #define SYS_ICC_IAR1_EL1		sys_reg(3, 0, 12, 12, 0)
> >>  #define SYS_ICC_EOIR1_EL1		sys_reg(3, 0, 12, 12, 1)
> >> +#define SYS_ICC_HPPIR1_EL1		sys_reg(3, 0, 12, 12, 2)
> >>  #define SYS_ICC_BPR1_EL1		sys_reg(3, 0, 12, 12, 3)
> >>  #define SYS_ICC_CTLR_EL1		sys_reg(3, 0, 12, 12, 4)
> >>  #define SYS_ICC_SRE_EL1			sys_reg(3, 0, 12, 12, 5)
> >> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> index d4f07f84602d..f0bc711db258 100644
> >> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> @@ -772,6 +772,26 @@ static void __hyp_text __vgic_v3_write_apxr3(struct kvm_vcpu *vcpu,
> >>  	__vgic_v3_write_apxrn(vcpu, rt, 3);
> >>  }
> >>  
> >> +static void __hyp_text __vgic_v3_read_hppir(struct kvm_vcpu *vcpu,
> >> +					    u32 vmcr, int rt)
> >> +{
> >> +	u64 lr_val;
> >> +	int lr, lr_grp, grp;
> >> +
> >> +	grp = __vgic_v3_get_group(vcpu);
> >> +
> >> +	lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val);
> >> +	if (lr == -1)
> >> +		goto spurious;
> >> +
> >> +	lr_grp = !!(lr_val & ICH_LR_GROUP);
> >> +	if (lr_grp != grp)
> >> +		lr_val = ICC_IAR1_EL1_SPURIOUS;
> > 
> > I don't get this.  The spec says that the special INTID 1023
> >   "...is returned in response to an interrupt acknowledge, if there is
> >    no pending interrupt with sufficient priority for it to be signaled to
> >    the PE, or if the highest priority pending interrupt is not
> >    appropriate for the:
> >     * Current Security state.  Interrupt group that is associated with
> >     * the System register."
> > 
> > So do we just take this to imply that it also covers the HPPIRx_EL1
> > registers (despite them being mentioned explicitly for the other special
> > INTIDs) or is there some other piece of spec I'm missing here?
> 
> Here's what the ICV_HPPIRx_EL1 INTID description says:
> 
> "If the highest priority pending interrupt is not observable, this field
> contains a special INTID to indicate the reason. This special INTID can
> take the value 1023 only."
> 
> Yes, the disparity between ICC_HPPIRx_EL1 and ICV_HPPIRx_EL1 is very
> confusing and makes me want to shout at people.
> 

ok, shitty spec.

Thanks,
-Christoffer

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

* Re: [PATCH v2 12/25] KVM: arm64: Enable GICv3 Group-1 sysreg trapping via command-line
  2017-06-06 13:59       ` Marc Zyngier
@ 2017-06-06 14:42         ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 14:42 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter,
	linux-arm-kernel, kvmarm

On Tue, Jun 06, 2017 at 02:59:34PM +0100, Marc Zyngier wrote:
> On 06/06/17 13:06, Christoffer Dall wrote:
> > On Thu, Jun 01, 2017 at 11:21:04AM +0100, Marc Zyngier wrote:
> >> Now that we're able to safely handle Group-1 sysreg access, let's
> >> give the user the opportunity to enable it by passing a specific
> >> command-line option (vgic_v3.group1_trap).
> >>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> ---
> >>  virt/kvm/arm/hyp/vgic-v3-sr.c |  6 +++++-
> >>  virt/kvm/arm/vgic/vgic-v3.c   | 11 +++++++++++
> >>  2 files changed, 16 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> index 8973bad35748..42ac9ee7650a 100644
> >> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> @@ -334,7 +334,11 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
> >>  		for (i = 0; i < used_lrs; i++)
> >>  			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
> >>  	} else {
> >> -		/* Always write ICH_HCR_EL2 to enable trapping */
> >> +		/*
> >> +                 * If we don't have any interrupt to inject, but that
> >> +		 * trapping is enabled, write the ICH_HCR_EL2 config
> >> +		 * anyway.
> >> +		 */
> > 
> > nit: Whitespace and grammar issues, and maybe this hunk was supposed to
> > be in the last patch?
> 
> Indeed, on both counts.
> 
> > 
> >>  		if (static_branch_unlikely(&vgic_v3_cpuif_trap))
> >>  			write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
> >>  	}
> >> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> >> index fbd678bc046d..a16769276efd 100644
> >> --- a/virt/kvm/arm/vgic/vgic-v3.c
> >> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> >> @@ -416,6 +416,12 @@ int vgic_v3_map_resources(struct kvm *kvm)
> >>  
> >>  DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap);
> >>  
> >> +static int __init early_group1_trap_cfg(char *buf)
> >> +{
> >> +	return strtobool(buf, &group1_trap);
> >> +}
> >> +early_param("vgic_v3.group1_trap", early_group1_trap_cfg);
> >> +
> > 
> > this shouldn't be named something with KVM (we're not going to trap
> > anything on the host somehow are we?)?
> 
> Good point. kvm_vgic_v3.whatever?
> 

Yeah, sounds fine.

Thanks,
-Christoffer

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

* [PATCH v2 12/25] KVM: arm64: Enable GICv3 Group-1 sysreg trapping via command-line
@ 2017-06-06 14:42         ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 14:42 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jun 06, 2017 at 02:59:34PM +0100, Marc Zyngier wrote:
> On 06/06/17 13:06, Christoffer Dall wrote:
> > On Thu, Jun 01, 2017 at 11:21:04AM +0100, Marc Zyngier wrote:
> >> Now that we're able to safely handle Group-1 sysreg access, let's
> >> give the user the opportunity to enable it by passing a specific
> >> command-line option (vgic_v3.group1_trap).
> >>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> ---
> >>  virt/kvm/arm/hyp/vgic-v3-sr.c |  6 +++++-
> >>  virt/kvm/arm/vgic/vgic-v3.c   | 11 +++++++++++
> >>  2 files changed, 16 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> index 8973bad35748..42ac9ee7650a 100644
> >> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> @@ -334,7 +334,11 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
> >>  		for (i = 0; i < used_lrs; i++)
> >>  			__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
> >>  	} else {
> >> -		/* Always write ICH_HCR_EL2 to enable trapping */
> >> +		/*
> >> +                 * If we don't have any interrupt to inject, but that
> >> +		 * trapping is enabled, write the ICH_HCR_EL2 config
> >> +		 * anyway.
> >> +		 */
> > 
> > nit: Whitespace and grammar issues, and maybe this hunk was supposed to
> > be in the last patch?
> 
> Indeed, on both counts.
> 
> > 
> >>  		if (static_branch_unlikely(&vgic_v3_cpuif_trap))
> >>  			write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
> >>  	}
> >> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> >> index fbd678bc046d..a16769276efd 100644
> >> --- a/virt/kvm/arm/vgic/vgic-v3.c
> >> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> >> @@ -416,6 +416,12 @@ int vgic_v3_map_resources(struct kvm *kvm)
> >>  
> >>  DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap);
> >>  
> >> +static int __init early_group1_trap_cfg(char *buf)
> >> +{
> >> +	return strtobool(buf, &group1_trap);
> >> +}
> >> +early_param("vgic_v3.group1_trap", early_group1_trap_cfg);
> >> +
> > 
> > this shouldn't be named something with KVM (we're not going to trap
> > anything on the host somehow are we?)?
> 
> Good point. kvm_vgic_v3.whatever?
> 

Yeah, sounds fine.

Thanks,
-Christoffer

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

* Re: [PATCH v2 13/25] KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler
  2017-06-06 12:11     ` Christoffer Dall
@ 2017-06-06 15:15       ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-06 15:15 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter,
	linux-arm-kernel, kvmarm

On 06/06/17 13:11, Christoffer Dall wrote:
> On Thu, Jun 01, 2017 at 11:21:05AM +0100, Marc Zyngier wrote:
>> Add a handler for reading/writing the guest's view of the ICC_BPR0_EL1
>> register, which is located in the ICH_VMCR_EL2.BPR0 field.
>>
>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  arch/arm64/include/asm/sysreg.h |  1 +
>>  virt/kvm/arm/hyp/vgic-v3-sr.c   | 36 ++++++++++++++++++++++++++++++++++++
>>  2 files changed, 37 insertions(+)
>>
>> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
>> index bd000686194a..d20be0b28ca4 100644
>> --- a/arch/arm64/include/asm/sysreg.h
>> +++ b/arch/arm64/include/asm/sysreg.h
>> @@ -180,6 +180,7 @@
>>  
>>  #define SYS_VBAR_EL1			sys_reg(3, 0, 12, 0, 0)
>>  
>> +#define SYS_ICC_BPR0_EL1		sys_reg(3, 0, 12, 8, 3)
>>  #define SYS_ICC_AP1Rn_EL1(n)		sys_reg(3, 0, 12, 9, n)
>>  #define SYS_ICC_DIR_EL1			sys_reg(3, 0, 12, 11, 1)
>>  #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
>> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> index 42ac9ee7650a..54a8e828c85b 100644
>> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
>> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> @@ -688,11 +688,41 @@ static void __hyp_text __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr,
>>  	__vgic_v3_write_vmcr(vmcr);
>>  }
>>  
>> +static void __hyp_text __vgic_v3_read_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>> +{
>> +	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr0(vmcr));
>> +}
>> +
>>  static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>>  {
>>  	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
>>  }
>>  
>> +static void __hyp_text __vgic_v3_write_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>> +{
>> +	u64 val = vcpu_get_reg(vcpu, rt);
>> +	u8 bpr_min = 7 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
>> +
>> +	/* Enforce BPR limiting */
>> +	if (val < bpr_min)
>> +		val = bpr_min;
>> +
>> +	val <<= ICH_VMCR_BPR0_SHIFT;
>> +	val &= ICH_VMCR_BPR0_MASK;
>> +	vmcr &= ~ICH_VMCR_BPR0_MASK;
>> +	vmcr |= val;
>> +
>> +	if (vmcr & ICH_VMCR_CBPR_MASK) {
>> +		val = __vgic_v3_get_bpr1(vmcr);
>> +		val <<= ICH_VMCR_BPR1_SHIFT;
>> +		val &= ICH_VMCR_BPR1_MASK;
>> +		vmcr &= ~ICH_VMCR_BPR1_MASK;
>> +		vmcr |= val;
>> +	}
> 
> I don't understand why this block is needed?

If you have CBPR already set, and then update BPR0, you need to make
sure that BPR1 gets updated as well. You could hope that the HW would do
it for you, but since we're erratum workaround land...

Thanks,

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

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

* [PATCH v2 13/25] KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler
@ 2017-06-06 15:15       ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-06 15:15 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/06/17 13:11, Christoffer Dall wrote:
> On Thu, Jun 01, 2017 at 11:21:05AM +0100, Marc Zyngier wrote:
>> Add a handler for reading/writing the guest's view of the ICC_BPR0_EL1
>> register, which is located in the ICH_VMCR_EL2.BPR0 field.
>>
>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  arch/arm64/include/asm/sysreg.h |  1 +
>>  virt/kvm/arm/hyp/vgic-v3-sr.c   | 36 ++++++++++++++++++++++++++++++++++++
>>  2 files changed, 37 insertions(+)
>>
>> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
>> index bd000686194a..d20be0b28ca4 100644
>> --- a/arch/arm64/include/asm/sysreg.h
>> +++ b/arch/arm64/include/asm/sysreg.h
>> @@ -180,6 +180,7 @@
>>  
>>  #define SYS_VBAR_EL1			sys_reg(3, 0, 12, 0, 0)
>>  
>> +#define SYS_ICC_BPR0_EL1		sys_reg(3, 0, 12, 8, 3)
>>  #define SYS_ICC_AP1Rn_EL1(n)		sys_reg(3, 0, 12, 9, n)
>>  #define SYS_ICC_DIR_EL1			sys_reg(3, 0, 12, 11, 1)
>>  #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
>> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> index 42ac9ee7650a..54a8e828c85b 100644
>> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
>> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
>> @@ -688,11 +688,41 @@ static void __hyp_text __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr,
>>  	__vgic_v3_write_vmcr(vmcr);
>>  }
>>  
>> +static void __hyp_text __vgic_v3_read_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>> +{
>> +	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr0(vmcr));
>> +}
>> +
>>  static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>>  {
>>  	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
>>  }
>>  
>> +static void __hyp_text __vgic_v3_write_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>> +{
>> +	u64 val = vcpu_get_reg(vcpu, rt);
>> +	u8 bpr_min = 7 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
>> +
>> +	/* Enforce BPR limiting */
>> +	if (val < bpr_min)
>> +		val = bpr_min;
>> +
>> +	val <<= ICH_VMCR_BPR0_SHIFT;
>> +	val &= ICH_VMCR_BPR0_MASK;
>> +	vmcr &= ~ICH_VMCR_BPR0_MASK;
>> +	vmcr |= val;
>> +
>> +	if (vmcr & ICH_VMCR_CBPR_MASK) {
>> +		val = __vgic_v3_get_bpr1(vmcr);
>> +		val <<= ICH_VMCR_BPR1_SHIFT;
>> +		val &= ICH_VMCR_BPR1_MASK;
>> +		vmcr &= ~ICH_VMCR_BPR1_MASK;
>> +		vmcr |= val;
>> +	}
> 
> I don't understand why this block is needed?

If you have CBPR already set, and then update BPR0, you need to make
sure that BPR1 gets updated as well. You could hope that the HW would do
it for you, but since we're erratum workaround land...

Thanks,

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

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

* Re: [PATCH v2 17/25] KVM: arm64: Enable GICv3 Group-0 sysreg trapping via command-line
  2017-06-06 12:44     ` Christoffer Dall
@ 2017-06-06 15:15       ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-06 15:15 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On 06/06/17 13:44, Christoffer Dall wrote:
> On Thu, Jun 01, 2017 at 11:21:09AM +0100, Marc Zyngier wrote:
>> Now that we're able to safely handle Group-0 sysreg access, let's
>> give the user the opportunity to enable it by passing a specific
>> command-line option (vgic_v3.group0_trap).
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic-v3.c | 6 ++++++
>>  1 file changed, 6 insertions(+)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>> index 7525216ef988..1486ce25edcb 100644
>> --- a/virt/kvm/arm/vgic/vgic-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>> @@ -419,6 +419,12 @@ int vgic_v3_map_resources(struct kvm *kvm)
>>  
>>  DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap);
>>  
>> +static int __init early_group0_trap_cfg(char *buf)
>> +{
>> +	return strtobool(buf, &group0_trap);
>> +}
>> +early_param("vgic_v3.group0_trap", early_group0_trap_cfg);
>> +
> 
> same comment as before, if this should be called something with KVM.
> 
> Also, btw., what's the policy on adding new kernel parameters?  Should
> they be documented in kernel-parameters.txt or is that auto-generated
> these days?

I guess I should add something indeed.

Thanks,

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

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

* [PATCH v2 17/25] KVM: arm64: Enable GICv3 Group-0 sysreg trapping via command-line
@ 2017-06-06 15:15       ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-06 15:15 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/06/17 13:44, Christoffer Dall wrote:
> On Thu, Jun 01, 2017 at 11:21:09AM +0100, Marc Zyngier wrote:
>> Now that we're able to safely handle Group-0 sysreg access, let's
>> give the user the opportunity to enable it by passing a specific
>> command-line option (vgic_v3.group0_trap).
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  virt/kvm/arm/vgic/vgic-v3.c | 6 ++++++
>>  1 file changed, 6 insertions(+)
>>
>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>> index 7525216ef988..1486ce25edcb 100644
>> --- a/virt/kvm/arm/vgic/vgic-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>> @@ -419,6 +419,12 @@ int vgic_v3_map_resources(struct kvm *kvm)
>>  
>>  DEFINE_STATIC_KEY_FALSE(vgic_v3_cpuif_trap);
>>  
>> +static int __init early_group0_trap_cfg(char *buf)
>> +{
>> +	return strtobool(buf, &group0_trap);
>> +}
>> +early_param("vgic_v3.group0_trap", early_group0_trap_cfg);
>> +
> 
> same comment as before, if this should be called something with KVM.
> 
> Also, btw., what's the policy on adding new kernel parameters?  Should
> they be documented in kernel-parameters.txt or is that auto-generated
> these days?

I guess I should add something indeed.

Thanks,

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

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

* Re: [PATCH v2 19/25] arm64: Add workaround for Cavium Thunder erratum 30115
  2017-06-06 12:48     ` Christoffer Dall
@ 2017-06-06 15:18       ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-06 15:18 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On 06/06/17 13:48, Christoffer Dall wrote:
> On Thu, Jun 01, 2017 at 11:21:11AM +0100, Marc Zyngier wrote:
>> From: David Daney <david.daney@cavium.com>
>>
>> Some Cavium Thunder CPUs suffer a problem where a KVM guest may
>> inadvertently cause the host kernel to quit receiving interrupts.
>>
>> Use the Group-0/1 trapping in order to deal with it.
>>
>> [maz]: Adapted patch to the Group-0/1 trapping, reworked commit log
>>
>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>> Signed-off-by: David Daney <david.daney@cavium.com>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  Documentation/arm64/silicon-errata.txt |  1 +
>>  arch/arm64/Kconfig                     | 11 +++++++++++
>>  arch/arm64/include/asm/cpucaps.h       |  3 ++-
>>  arch/arm64/kernel/cpu_errata.c         | 21 +++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic-v3.c            |  7 +++++++
>>  5 files changed, 42 insertions(+), 1 deletion(-)
>>
>> diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt
>> index 10f2dddbf449..f5f93dca54b7 100644
>> --- a/Documentation/arm64/silicon-errata.txt
>> +++ b/Documentation/arm64/silicon-errata.txt
>> @@ -62,6 +62,7 @@ stable kernels.
>>  | Cavium         | ThunderX GICv3  | #23154          | CAVIUM_ERRATUM_23154        |
>>  | Cavium         | ThunderX Core   | #27456          | CAVIUM_ERRATUM_27456        |
>>  | Cavium         | ThunderX SMMUv2 | #27704          | N/A                         |
>> +| Cavium         | ThunderX Core   | #30115          | CAVIUM_ERRATUM_30115        |
>>  |                |                 |                 |                             |
>>  | Freescale/NXP  | LS2080A/LS1043A | A-008585        | FSL_ERRATUM_A008585         |
>>  |                |                 |                 |                             |
>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>> index 3dcd7ec69bca..0950b21e4d17 100644
>> --- a/arch/arm64/Kconfig
>> +++ b/arch/arm64/Kconfig
>> @@ -480,6 +480,17 @@ config CAVIUM_ERRATUM_27456
>>  
>>  	  If unsure, say Y.
>>  
>> +config CAVIUM_ERRATUM_30115
>> +	bool "Cavium erratum 30115: Guest may disable interrupts in host"
>> +	default y
>> +	help
>> +	  On ThunderX T88 pass 1.x through 2.2, T81 pass 1.0 through
>> +	  1.2, and T83 Pass 1.0, KVM guest execution may disable
>> +	  interrupts in host. Trapping GICv3 group-1 accesses sidesteps
>> +	  the issue.
>> +
>> +	  If unsure, say Y.
>> +
>>  config QCOM_FALKOR_ERRATUM_1003
>>  	bool "Falkor E1003: Incorrect translation due to ASID change"
>>  	default y
>> diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
>> index b3aab8a17868..8d2272c6822c 100644
>> --- a/arch/arm64/include/asm/cpucaps.h
>> +++ b/arch/arm64/include/asm/cpucaps.h
>> @@ -38,7 +38,8 @@
>>  #define ARM64_WORKAROUND_REPEAT_TLBI		17
>>  #define ARM64_WORKAROUND_QCOM_FALKOR_E1003	18
>>  #define ARM64_WORKAROUND_858921			19
>> +#define ARM64_WORKAROUND_CAVIUM_30115		20
>>  
>> -#define ARM64_NCAPS				20
>> +#define ARM64_NCAPS				21
>>  
>>  #endif /* __ASM_CPUCAPS_H */
>> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
>> index 2ed2a7657711..0e27f86ee709 100644
>> --- a/arch/arm64/kernel/cpu_errata.c
>> +++ b/arch/arm64/kernel/cpu_errata.c
>> @@ -133,6 +133,27 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
>>  		MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x00),
>>  	},
>>  #endif
>> +#ifdef CONFIG_CAVIUM_ERRATUM_30115
>> +	{
>> +	/* Cavium ThunderX, T88 pass 1.x - 2.2 */
>> +		.desc = "Cavium erratum 30115",
>> +		.capability = ARM64_WORKAROUND_CAVIUM_30115,
>> +		MIDR_RANGE(MIDR_THUNDERX, 0x00,
>> +			   (1 << MIDR_VARIANT_SHIFT) | 2),
>> +	},
>> +	{
>> +	/* Cavium ThunderX, T81 pass 1.0 - 1.2 */
>> +		.desc = "Cavium erratum 30115",
>> +		.capability = ARM64_WORKAROUND_CAVIUM_30115,
>> +		MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x02),
>> +	},
>> +	{
>> +	/* Cavium ThunderX, T83 pass 1.0 */
>> +		.desc = "Cavium erratum 30115",
>> +		.capability = ARM64_WORKAROUND_CAVIUM_30115,
>> +		MIDR_RANGE(MIDR_THUNDERX_83XX, 0x00, 0x00),
>> +	},
>> +#endif
>>  	{
>>  		.desc = "Mismatched cache line size",
>>  		.capability = ARM64_MISMATCHED_CACHE_LINE_SIZE,
>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>> index 1486ce25edcb..062be1fe95b5 100644
>> --- a/virt/kvm/arm/vgic/vgic-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>> @@ -482,6 +482,13 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
>>  	if (kvm_vgic_global_state.vcpu_base == 0)
>>  		kvm_info("disabling GICv2 emulation\n");
>>  
>> +#ifdef CONFIG_ARM64
>> +	if (cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_30115)) {
>> +		group0_trap = true;
>> +		group1_trap = true;
> 
> Why does the config help text say that trapping group 1 accesses is
> enough, yet we trap both group 0 and group 1 ?

Ah, I missed the help text when adapting the original patch. My bad.
I'll fix that.

Thanks,

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

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

* [PATCH v2 19/25] arm64: Add workaround for Cavium Thunder erratum 30115
@ 2017-06-06 15:18       ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-06 15:18 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/06/17 13:48, Christoffer Dall wrote:
> On Thu, Jun 01, 2017 at 11:21:11AM +0100, Marc Zyngier wrote:
>> From: David Daney <david.daney@cavium.com>
>>
>> Some Cavium Thunder CPUs suffer a problem where a KVM guest may
>> inadvertently cause the host kernel to quit receiving interrupts.
>>
>> Use the Group-0/1 trapping in order to deal with it.
>>
>> [maz]: Adapted patch to the Group-0/1 trapping, reworked commit log
>>
>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>> Signed-off-by: David Daney <david.daney@cavium.com>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  Documentation/arm64/silicon-errata.txt |  1 +
>>  arch/arm64/Kconfig                     | 11 +++++++++++
>>  arch/arm64/include/asm/cpucaps.h       |  3 ++-
>>  arch/arm64/kernel/cpu_errata.c         | 21 +++++++++++++++++++++
>>  virt/kvm/arm/vgic/vgic-v3.c            |  7 +++++++
>>  5 files changed, 42 insertions(+), 1 deletion(-)
>>
>> diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt
>> index 10f2dddbf449..f5f93dca54b7 100644
>> --- a/Documentation/arm64/silicon-errata.txt
>> +++ b/Documentation/arm64/silicon-errata.txt
>> @@ -62,6 +62,7 @@ stable kernels.
>>  | Cavium         | ThunderX GICv3  | #23154          | CAVIUM_ERRATUM_23154        |
>>  | Cavium         | ThunderX Core   | #27456          | CAVIUM_ERRATUM_27456        |
>>  | Cavium         | ThunderX SMMUv2 | #27704          | N/A                         |
>> +| Cavium         | ThunderX Core   | #30115          | CAVIUM_ERRATUM_30115        |
>>  |                |                 |                 |                             |
>>  | Freescale/NXP  | LS2080A/LS1043A | A-008585        | FSL_ERRATUM_A008585         |
>>  |                |                 |                 |                             |
>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>> index 3dcd7ec69bca..0950b21e4d17 100644
>> --- a/arch/arm64/Kconfig
>> +++ b/arch/arm64/Kconfig
>> @@ -480,6 +480,17 @@ config CAVIUM_ERRATUM_27456
>>  
>>  	  If unsure, say Y.
>>  
>> +config CAVIUM_ERRATUM_30115
>> +	bool "Cavium erratum 30115: Guest may disable interrupts in host"
>> +	default y
>> +	help
>> +	  On ThunderX T88 pass 1.x through 2.2, T81 pass 1.0 through
>> +	  1.2, and T83 Pass 1.0, KVM guest execution may disable
>> +	  interrupts in host. Trapping GICv3 group-1 accesses sidesteps
>> +	  the issue.
>> +
>> +	  If unsure, say Y.
>> +
>>  config QCOM_FALKOR_ERRATUM_1003
>>  	bool "Falkor E1003: Incorrect translation due to ASID change"
>>  	default y
>> diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
>> index b3aab8a17868..8d2272c6822c 100644
>> --- a/arch/arm64/include/asm/cpucaps.h
>> +++ b/arch/arm64/include/asm/cpucaps.h
>> @@ -38,7 +38,8 @@
>>  #define ARM64_WORKAROUND_REPEAT_TLBI		17
>>  #define ARM64_WORKAROUND_QCOM_FALKOR_E1003	18
>>  #define ARM64_WORKAROUND_858921			19
>> +#define ARM64_WORKAROUND_CAVIUM_30115		20
>>  
>> -#define ARM64_NCAPS				20
>> +#define ARM64_NCAPS				21
>>  
>>  #endif /* __ASM_CPUCAPS_H */
>> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
>> index 2ed2a7657711..0e27f86ee709 100644
>> --- a/arch/arm64/kernel/cpu_errata.c
>> +++ b/arch/arm64/kernel/cpu_errata.c
>> @@ -133,6 +133,27 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
>>  		MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x00),
>>  	},
>>  #endif
>> +#ifdef CONFIG_CAVIUM_ERRATUM_30115
>> +	{
>> +	/* Cavium ThunderX, T88 pass 1.x - 2.2 */
>> +		.desc = "Cavium erratum 30115",
>> +		.capability = ARM64_WORKAROUND_CAVIUM_30115,
>> +		MIDR_RANGE(MIDR_THUNDERX, 0x00,
>> +			   (1 << MIDR_VARIANT_SHIFT) | 2),
>> +	},
>> +	{
>> +	/* Cavium ThunderX, T81 pass 1.0 - 1.2 */
>> +		.desc = "Cavium erratum 30115",
>> +		.capability = ARM64_WORKAROUND_CAVIUM_30115,
>> +		MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x02),
>> +	},
>> +	{
>> +	/* Cavium ThunderX, T83 pass 1.0 */
>> +		.desc = "Cavium erratum 30115",
>> +		.capability = ARM64_WORKAROUND_CAVIUM_30115,
>> +		MIDR_RANGE(MIDR_THUNDERX_83XX, 0x00, 0x00),
>> +	},
>> +#endif
>>  	{
>>  		.desc = "Mismatched cache line size",
>>  		.capability = ARM64_MISMATCHED_CACHE_LINE_SIZE,
>> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
>> index 1486ce25edcb..062be1fe95b5 100644
>> --- a/virt/kvm/arm/vgic/vgic-v3.c
>> +++ b/virt/kvm/arm/vgic/vgic-v3.c
>> @@ -482,6 +482,13 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
>>  	if (kvm_vgic_global_state.vcpu_base == 0)
>>  		kvm_info("disabling GICv2 emulation\n");
>>  
>> +#ifdef CONFIG_ARM64
>> +	if (cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_30115)) {
>> +		group0_trap = true;
>> +		group1_trap = true;
> 
> Why does the config help text say that trapping group 1 accesses is
> enough, yet we trap both group 0 and group 1 ?

Ah, I missed the help text when adapting the original patch. My bad.
I'll fix that.

Thanks,

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

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

* Re: [PATCH v2 13/25] KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler
  2017-06-06 15:15       ` Marc Zyngier
@ 2017-06-06 15:46         ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 15:46 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Christoffer Dall, David Daney, Catalin Marinas, Mark Rutland,
	Robert Richter, Eric Auger, kvmarm, linux-arm-kernel, kvm

On Tue, Jun 06, 2017 at 04:15:05PM +0100, Marc Zyngier wrote:
> On 06/06/17 13:11, Christoffer Dall wrote:
> > On Thu, Jun 01, 2017 at 11:21:05AM +0100, Marc Zyngier wrote:
> >> Add a handler for reading/writing the guest's view of the ICC_BPR0_EL1
> >> register, which is located in the ICH_VMCR_EL2.BPR0 field.
> >>
> >> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> ---
> >>  arch/arm64/include/asm/sysreg.h |  1 +
> >>  virt/kvm/arm/hyp/vgic-v3-sr.c   | 36 ++++++++++++++++++++++++++++++++++++
> >>  2 files changed, 37 insertions(+)
> >>
> >> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> >> index bd000686194a..d20be0b28ca4 100644
> >> --- a/arch/arm64/include/asm/sysreg.h
> >> +++ b/arch/arm64/include/asm/sysreg.h
> >> @@ -180,6 +180,7 @@
> >>  
> >>  #define SYS_VBAR_EL1			sys_reg(3, 0, 12, 0, 0)
> >>  
> >> +#define SYS_ICC_BPR0_EL1		sys_reg(3, 0, 12, 8, 3)
> >>  #define SYS_ICC_AP1Rn_EL1(n)		sys_reg(3, 0, 12, 9, n)
> >>  #define SYS_ICC_DIR_EL1			sys_reg(3, 0, 12, 11, 1)
> >>  #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
> >> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> index 42ac9ee7650a..54a8e828c85b 100644
> >> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> @@ -688,11 +688,41 @@ static void __hyp_text __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr,
> >>  	__vgic_v3_write_vmcr(vmcr);
> >>  }
> >>  
> >> +static void __hyp_text __vgic_v3_read_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >> +{
> >> +	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr0(vmcr));
> >> +}
> >> +
> >>  static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >>  {
> >>  	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
> >>  }
> >>  
> >> +static void __hyp_text __vgic_v3_write_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >> +{
> >> +	u64 val = vcpu_get_reg(vcpu, rt);
> >> +	u8 bpr_min = 7 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> >> +
> >> +	/* Enforce BPR limiting */
> >> +	if (val < bpr_min)
> >> +		val = bpr_min;
> >> +
> >> +	val <<= ICH_VMCR_BPR0_SHIFT;
> >> +	val &= ICH_VMCR_BPR0_MASK;
> >> +	vmcr &= ~ICH_VMCR_BPR0_MASK;
> >> +	vmcr |= val;
> >> +
> >> +	if (vmcr & ICH_VMCR_CBPR_MASK) {
> >> +		val = __vgic_v3_get_bpr1(vmcr);
> >> +		val <<= ICH_VMCR_BPR1_SHIFT;
> >> +		val &= ICH_VMCR_BPR1_MASK;
> >> +		vmcr &= ~ICH_VMCR_BPR1_MASK;
> >> +		vmcr |= val;
> >> +	}
> > 
> > I don't understand why this block is needed?
> 
> If you have CBPR already set, and then update BPR0, you need to make
> sure that BPR1 gets updated as well. You could hope that the HW would do
> it for you, but since we're erratum workaround land...
> 

I just didn't read the spec that way, I gathered that the hardware would
maintain read-as-written for for bpr1 but use bpr0 to set the binary
point when cbpr is set, and just ignore writes to bpr1 for as long as
cbpr is set.

In any case, probably doesn't matter, but I was just curious if the spec
dictateted this behavior and if we should reference that part of the
spec in a comment then.

Thanks,
-Christoffer

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

* [PATCH v2 13/25] KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler
@ 2017-06-06 15:46         ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 15:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jun 06, 2017 at 04:15:05PM +0100, Marc Zyngier wrote:
> On 06/06/17 13:11, Christoffer Dall wrote:
> > On Thu, Jun 01, 2017 at 11:21:05AM +0100, Marc Zyngier wrote:
> >> Add a handler for reading/writing the guest's view of the ICC_BPR0_EL1
> >> register, which is located in the ICH_VMCR_EL2.BPR0 field.
> >>
> >> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> >> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> >> ---
> >>  arch/arm64/include/asm/sysreg.h |  1 +
> >>  virt/kvm/arm/hyp/vgic-v3-sr.c   | 36 ++++++++++++++++++++++++++++++++++++
> >>  2 files changed, 37 insertions(+)
> >>
> >> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> >> index bd000686194a..d20be0b28ca4 100644
> >> --- a/arch/arm64/include/asm/sysreg.h
> >> +++ b/arch/arm64/include/asm/sysreg.h
> >> @@ -180,6 +180,7 @@
> >>  
> >>  #define SYS_VBAR_EL1			sys_reg(3, 0, 12, 0, 0)
> >>  
> >> +#define SYS_ICC_BPR0_EL1		sys_reg(3, 0, 12, 8, 3)
> >>  #define SYS_ICC_AP1Rn_EL1(n)		sys_reg(3, 0, 12, 9, n)
> >>  #define SYS_ICC_DIR_EL1			sys_reg(3, 0, 12, 11, 1)
> >>  #define SYS_ICC_SGI1R_EL1		sys_reg(3, 0, 12, 11, 5)
> >> diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> index 42ac9ee7650a..54a8e828c85b 100644
> >> --- a/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> +++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
> >> @@ -688,11 +688,41 @@ static void __hyp_text __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr,
> >>  	__vgic_v3_write_vmcr(vmcr);
> >>  }
> >>  
> >> +static void __hyp_text __vgic_v3_read_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >> +{
> >> +	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr0(vmcr));
> >> +}
> >> +
> >>  static void __hyp_text __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >>  {
> >>  	vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr));
> >>  }
> >>  
> >> +static void __hyp_text __vgic_v3_write_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >> +{
> >> +	u64 val = vcpu_get_reg(vcpu, rt);
> >> +	u8 bpr_min = 7 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> >> +
> >> +	/* Enforce BPR limiting */
> >> +	if (val < bpr_min)
> >> +		val = bpr_min;
> >> +
> >> +	val <<= ICH_VMCR_BPR0_SHIFT;
> >> +	val &= ICH_VMCR_BPR0_MASK;
> >> +	vmcr &= ~ICH_VMCR_BPR0_MASK;
> >> +	vmcr |= val;
> >> +
> >> +	if (vmcr & ICH_VMCR_CBPR_MASK) {
> >> +		val = __vgic_v3_get_bpr1(vmcr);
> >> +		val <<= ICH_VMCR_BPR1_SHIFT;
> >> +		val &= ICH_VMCR_BPR1_MASK;
> >> +		vmcr &= ~ICH_VMCR_BPR1_MASK;
> >> +		vmcr |= val;
> >> +	}
> > 
> > I don't understand why this block is needed?
> 
> If you have CBPR already set, and then update BPR0, you need to make
> sure that BPR1 gets updated as well. You could hope that the HW would do
> it for you, but since we're erratum workaround land...
> 

I just didn't read the spec that way, I gathered that the hardware would
maintain read-as-written for for bpr1 but use bpr0 to set the binary
point when cbpr is set, and just ignore writes to bpr1 for as long as
cbpr is set.

In any case, probably doesn't matter, but I was just curious if the spec
dictateted this behavior and if we should reference that part of the
spec in a comment then.

Thanks,
-Christoffer

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

* Re: [PATCH v2 13/25] KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler
  2017-06-06 15:46         ` Christoffer Dall
@ 2017-06-06 15:56           ` Peter Maydell
  -1 siblings, 0 replies; 152+ messages in thread
From: Peter Maydell @ 2017-06-06 15:56 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Marc Zyngier, kvm-devel, David Daney, Catalin Marinas,
	Robert Richter, arm-mail-list, kvmarm

On 6 June 2017 at 16:46, Christoffer Dall <cdall@linaro.org> wrote:
> On Tue, Jun 06, 2017 at 04:15:05PM +0100, Marc Zyngier wrote:
>> >> +static void __hyp_text __vgic_v3_write_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>> >> +{
>> >> +  u64 val = vcpu_get_reg(vcpu, rt);
>> >> +  u8 bpr_min = 7 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
>> >> +
>> >> +  /* Enforce BPR limiting */
>> >> +  if (val < bpr_min)
>> >> +          val = bpr_min;
>> >> +
>> >> +  val <<= ICH_VMCR_BPR0_SHIFT;
>> >> +  val &= ICH_VMCR_BPR0_MASK;
>> >> +  vmcr &= ~ICH_VMCR_BPR0_MASK;
>> >> +  vmcr |= val;
>> >> +
>> >> +  if (vmcr & ICH_VMCR_CBPR_MASK) {
>> >> +          val = __vgic_v3_get_bpr1(vmcr);
>> >> +          val <<= ICH_VMCR_BPR1_SHIFT;
>> >> +          val &= ICH_VMCR_BPR1_MASK;
>> >> +          vmcr &= ~ICH_VMCR_BPR1_MASK;
>> >> +          vmcr |= val;
>> >> +  }
>> >
>> > I don't understand why this block is needed?
>>
>> If you have CBPR already set, and then update BPR0, you need to make
>> sure that BPR1 gets updated as well. You could hope that the HW would do
>> it for you, but since we're erratum workaround land...
>>
>
> I just didn't read the spec that way, I gathered that the hardware would
> maintain read-as-written for for bpr1 but use bpr0 to set the binary
> point when cbpr is set, and just ignore writes to bpr1 for as long as
> cbpr is set.

This depends whether you're talking about the ICC/ICV BPR0/BPR1 registers,
or the fields in the ICH_VMCR*. For the former, if CBPR is set then
BPR1 reads and writes affect BPR0. For the latter, the two fields
are both independent and read-as-written regardless of the value
of CBPR, it's just that the value in the BPR1 field has no effect.
(The reason for this is for VM state migration: if a guest does:
  - write X to BPR0
  - write Y to BPR1
  - set CBPR
  - write Z to BPR0
  - unset CBPR
  - read BPR1
it should get back Y still; so EL2 needs to have a way to see
both the underlying BPR0 and BPR1 values even if CPBR is in effect.)

So the code above is not correct, I think, because it's making
writes to BPR0 affect the BPR1 value. Instead what should happen
is that when we emulate reads and writes to ICC_BPR1 we should pay
attention to CBPR and work with either the VMCR BPR0 or BPR1 field
appropriately.

thanks
-- PMM

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

* [PATCH v2 13/25] KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler
@ 2017-06-06 15:56           ` Peter Maydell
  0 siblings, 0 replies; 152+ messages in thread
From: Peter Maydell @ 2017-06-06 15:56 UTC (permalink / raw)
  To: linux-arm-kernel

On 6 June 2017 at 16:46, Christoffer Dall <cdall@linaro.org> wrote:
> On Tue, Jun 06, 2017 at 04:15:05PM +0100, Marc Zyngier wrote:
>> >> +static void __hyp_text __vgic_v3_write_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>> >> +{
>> >> +  u64 val = vcpu_get_reg(vcpu, rt);
>> >> +  u8 bpr_min = 7 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
>> >> +
>> >> +  /* Enforce BPR limiting */
>> >> +  if (val < bpr_min)
>> >> +          val = bpr_min;
>> >> +
>> >> +  val <<= ICH_VMCR_BPR0_SHIFT;
>> >> +  val &= ICH_VMCR_BPR0_MASK;
>> >> +  vmcr &= ~ICH_VMCR_BPR0_MASK;
>> >> +  vmcr |= val;
>> >> +
>> >> +  if (vmcr & ICH_VMCR_CBPR_MASK) {
>> >> +          val = __vgic_v3_get_bpr1(vmcr);
>> >> +          val <<= ICH_VMCR_BPR1_SHIFT;
>> >> +          val &= ICH_VMCR_BPR1_MASK;
>> >> +          vmcr &= ~ICH_VMCR_BPR1_MASK;
>> >> +          vmcr |= val;
>> >> +  }
>> >
>> > I don't understand why this block is needed?
>>
>> If you have CBPR already set, and then update BPR0, you need to make
>> sure that BPR1 gets updated as well. You could hope that the HW would do
>> it for you, but since we're erratum workaround land...
>>
>
> I just didn't read the spec that way, I gathered that the hardware would
> maintain read-as-written for for bpr1 but use bpr0 to set the binary
> point when cbpr is set, and just ignore writes to bpr1 for as long as
> cbpr is set.

This depends whether you're talking about the ICC/ICV BPR0/BPR1 registers,
or the fields in the ICH_VMCR*. For the former, if CBPR is set then
BPR1 reads and writes affect BPR0. For the latter, the two fields
are both independent and read-as-written regardless of the value
of CBPR, it's just that the value in the BPR1 field has no effect.
(The reason for this is for VM state migration: if a guest does:
  - write X to BPR0
  - write Y to BPR1
  - set CBPR
  - write Z to BPR0
  - unset CBPR
  - read BPR1
it should get back Y still; so EL2 needs to have a way to see
both the underlying BPR0 and BPR1 values even if CPBR is in effect.)

So the code above is not correct, I think, because it's making
writes to BPR0 affect the BPR1 value. Instead what should happen
is that when we emulate reads and writes to ICC_BPR1 we should pay
attention to CBPR and work with either the VMCR BPR0 or BPR1 field
appropriately.

thanks
-- PMM

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

* Re: [PATCH v2 13/25] KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler
  2017-06-06 15:56           ` Peter Maydell
@ 2017-06-06 16:56             ` Marc Zyngier
  -1 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-06 16:56 UTC (permalink / raw)
  To: Peter Maydell, Christoffer Dall
  Cc: kvm-devel, David Daney, Catalin Marinas, Robert Richter,
	arm-mail-list, kvmarm

On 06/06/17 16:56, Peter Maydell wrote:
> On 6 June 2017 at 16:46, Christoffer Dall <cdall@linaro.org> wrote:
>> On Tue, Jun 06, 2017 at 04:15:05PM +0100, Marc Zyngier wrote:
>>>>> +static void __hyp_text __vgic_v3_write_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>>>>> +{
>>>>> +  u64 val = vcpu_get_reg(vcpu, rt);
>>>>> +  u8 bpr_min = 7 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
>>>>> +
>>>>> +  /* Enforce BPR limiting */
>>>>> +  if (val < bpr_min)
>>>>> +          val = bpr_min;
>>>>> +
>>>>> +  val <<= ICH_VMCR_BPR0_SHIFT;
>>>>> +  val &= ICH_VMCR_BPR0_MASK;
>>>>> +  vmcr &= ~ICH_VMCR_BPR0_MASK;
>>>>> +  vmcr |= val;
>>>>> +
>>>>> +  if (vmcr & ICH_VMCR_CBPR_MASK) {
>>>>> +          val = __vgic_v3_get_bpr1(vmcr);
>>>>> +          val <<= ICH_VMCR_BPR1_SHIFT;
>>>>> +          val &= ICH_VMCR_BPR1_MASK;
>>>>> +          vmcr &= ~ICH_VMCR_BPR1_MASK;
>>>>> +          vmcr |= val;
>>>>> +  }
>>>>
>>>> I don't understand why this block is needed?
>>>
>>> If you have CBPR already set, and then update BPR0, you need to make
>>> sure that BPR1 gets updated as well. You could hope that the HW would do
>>> it for you, but since we're erratum workaround land...
>>>
>>
>> I just didn't read the spec that way, I gathered that the hardware would
>> maintain read-as-written for for bpr1 but use bpr0 to set the binary
>> point when cbpr is set, and just ignore writes to bpr1 for as long as
>> cbpr is set.
> 
> This depends whether you're talking about the ICC/ICV BPR0/BPR1 registers,
> or the fields in the ICH_VMCR*. For the former, if CBPR is set then
> BPR1 reads and writes affect BPR0. For the latter, the two fields
> are both independent and read-as-written regardless of the value
> of CBPR, it's just that the value in the BPR1 field has no effect.
> (The reason for this is for VM state migration: if a guest does:
>   - write X to BPR0
>   - write Y to BPR1
>   - set CBPR
>   - write Z to BPR0
>   - unset CBPR
>   - read BPR1
> it should get back Y still; so EL2 needs to have a way to see
> both the underlying BPR0 and BPR1 values even if CPBR is in effect.)
> 
> So the code above is not correct, I think, because it's making
> writes to BPR0 affect the BPR1 value. Instead what should happen
> is that when we emulate reads and writes to ICC_BPR1 we should pay
> attention to CBPR and work with either the VMCR BPR0 or BPR1 field
> appropriately.

The BPR1 accessors are already behaving that way (write ignored and read
as BPR0+1 if CBPR is set). But I didn't realize that you could mess with
CBPR and BPR0, and yet have ICH_VMCR_EL2.VBPR1 be unaffected.

I'll drop that hunk.

Thanks,

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

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

* [PATCH v2 13/25] KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler
@ 2017-06-06 16:56             ` Marc Zyngier
  0 siblings, 0 replies; 152+ messages in thread
From: Marc Zyngier @ 2017-06-06 16:56 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/06/17 16:56, Peter Maydell wrote:
> On 6 June 2017 at 16:46, Christoffer Dall <cdall@linaro.org> wrote:
>> On Tue, Jun 06, 2017 at 04:15:05PM +0100, Marc Zyngier wrote:
>>>>> +static void __hyp_text __vgic_v3_write_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
>>>>> +{
>>>>> +  u64 val = vcpu_get_reg(vcpu, rt);
>>>>> +  u8 bpr_min = 7 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
>>>>> +
>>>>> +  /* Enforce BPR limiting */
>>>>> +  if (val < bpr_min)
>>>>> +          val = bpr_min;
>>>>> +
>>>>> +  val <<= ICH_VMCR_BPR0_SHIFT;
>>>>> +  val &= ICH_VMCR_BPR0_MASK;
>>>>> +  vmcr &= ~ICH_VMCR_BPR0_MASK;
>>>>> +  vmcr |= val;
>>>>> +
>>>>> +  if (vmcr & ICH_VMCR_CBPR_MASK) {
>>>>> +          val = __vgic_v3_get_bpr1(vmcr);
>>>>> +          val <<= ICH_VMCR_BPR1_SHIFT;
>>>>> +          val &= ICH_VMCR_BPR1_MASK;
>>>>> +          vmcr &= ~ICH_VMCR_BPR1_MASK;
>>>>> +          vmcr |= val;
>>>>> +  }
>>>>
>>>> I don't understand why this block is needed?
>>>
>>> If you have CBPR already set, and then update BPR0, you need to make
>>> sure that BPR1 gets updated as well. You could hope that the HW would do
>>> it for you, but since we're erratum workaround land...
>>>
>>
>> I just didn't read the spec that way, I gathered that the hardware would
>> maintain read-as-written for for bpr1 but use bpr0 to set the binary
>> point when cbpr is set, and just ignore writes to bpr1 for as long as
>> cbpr is set.
> 
> This depends whether you're talking about the ICC/ICV BPR0/BPR1 registers,
> or the fields in the ICH_VMCR*. For the former, if CBPR is set then
> BPR1 reads and writes affect BPR0. For the latter, the two fields
> are both independent and read-as-written regardless of the value
> of CBPR, it's just that the value in the BPR1 field has no effect.
> (The reason for this is for VM state migration: if a guest does:
>   - write X to BPR0
>   - write Y to BPR1
>   - set CBPR
>   - write Z to BPR0
>   - unset CBPR
>   - read BPR1
> it should get back Y still; so EL2 needs to have a way to see
> both the underlying BPR0 and BPR1 values even if CPBR is in effect.)
> 
> So the code above is not correct, I think, because it's making
> writes to BPR0 affect the BPR1 value. Instead what should happen
> is that when we emulate reads and writes to ICC_BPR1 we should pay
> attention to CBPR and work with either the VMCR BPR0 or BPR1 field
> appropriately.

The BPR1 accessors are already behaving that way (write ignored and read
as BPR0+1 if CBPR is set). But I didn't realize that you could mess with
CBPR and BPR0, and yet have ICH_VMCR_EL2.VBPR1 be unaffected.

I'll drop that hunk.

Thanks,

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

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

* Re: [PATCH v2 13/25] KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler
  2017-06-06 15:56           ` Peter Maydell
@ 2017-06-06 17:23             ` Christoffer Dall
  -1 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 17:23 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Marc Zyngier, kvm-devel, David Daney, Catalin Marinas,
	Robert Richter, arm-mail-list, kvmarm

On Tue, Jun 06, 2017 at 04:56:27PM +0100, Peter Maydell wrote:
> On 6 June 2017 at 16:46, Christoffer Dall <cdall@linaro.org> wrote:
> > On Tue, Jun 06, 2017 at 04:15:05PM +0100, Marc Zyngier wrote:
> >> >> +static void __hyp_text __vgic_v3_write_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >> >> +{
> >> >> +  u64 val = vcpu_get_reg(vcpu, rt);
> >> >> +  u8 bpr_min = 7 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> >> >> +
> >> >> +  /* Enforce BPR limiting */
> >> >> +  if (val < bpr_min)
> >> >> +          val = bpr_min;
> >> >> +
> >> >> +  val <<= ICH_VMCR_BPR0_SHIFT;
> >> >> +  val &= ICH_VMCR_BPR0_MASK;
> >> >> +  vmcr &= ~ICH_VMCR_BPR0_MASK;
> >> >> +  vmcr |= val;
> >> >> +
> >> >> +  if (vmcr & ICH_VMCR_CBPR_MASK) {
> >> >> +          val = __vgic_v3_get_bpr1(vmcr);
> >> >> +          val <<= ICH_VMCR_BPR1_SHIFT;
> >> >> +          val &= ICH_VMCR_BPR1_MASK;
> >> >> +          vmcr &= ~ICH_VMCR_BPR1_MASK;
> >> >> +          vmcr |= val;
> >> >> +  }
> >> >
> >> > I don't understand why this block is needed?
> >>
> >> If you have CBPR already set, and then update BPR0, you need to make
> >> sure that BPR1 gets updated as well. You could hope that the HW would do
> >> it for you, but since we're erratum workaround land...
> >>
> >
> > I just didn't read the spec that way, I gathered that the hardware would
> > maintain read-as-written for for bpr1 but use bpr0 to set the binary
> > point when cbpr is set, and just ignore writes to bpr1 for as long as
> > cbpr is set.
> 
> This depends whether you're talking about the ICC/ICV BPR0/BPR1 registers,
> or the fields in the ICH_VMCR*. For the former, if CBPR is set then
> BPR1 reads and writes affect BPR0. 

>From the spec on ICV_BPR1_EL1: "Non-secure EL1 writes are ignored".
Doesn't that mean that reads of BPR1 reflect BPR0 but writes are
ignored?


> For the latter, the two fields
> are both independent and read-as-written regardless of the value
> of CBPR, it's just that the value in the BPR1 field has no effect.
> (The reason for this is for VM state migration: if a guest does:
>   - write X to BPR0
>   - write Y to BPR1
>   - set CBPR
>   - write Z to BPR0
>   - unset CBPR
>   - read BPR1
> it should get back Y still; so EL2 needs to have a way to see
> both the underlying BPR0 and BPR1 values even if CPBR is in effect.)
> 
> So the code above is not correct, I think, because it's making
> writes to BPR0 affect the BPR1 value. Instead what should happen
> is that when we emulate reads and writes to ICC_BPR1 we should pay
> attention to CBPR and work with either the VMCR BPR0 or BPR1 field
> appropriately.

I agree that we should drop the block above, but also think we should do
what we do in patch #5 and ignore writes to BPR1 if CBPR is set.

Thanks,
-Christoffer

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

* [PATCH v2 13/25] KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler
@ 2017-06-06 17:23             ` Christoffer Dall
  0 siblings, 0 replies; 152+ messages in thread
From: Christoffer Dall @ 2017-06-06 17:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jun 06, 2017 at 04:56:27PM +0100, Peter Maydell wrote:
> On 6 June 2017 at 16:46, Christoffer Dall <cdall@linaro.org> wrote:
> > On Tue, Jun 06, 2017 at 04:15:05PM +0100, Marc Zyngier wrote:
> >> >> +static void __hyp_text __vgic_v3_write_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
> >> >> +{
> >> >> +  u64 val = vcpu_get_reg(vcpu, rt);
> >> >> +  u8 bpr_min = 7 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2));
> >> >> +
> >> >> +  /* Enforce BPR limiting */
> >> >> +  if (val < bpr_min)
> >> >> +          val = bpr_min;
> >> >> +
> >> >> +  val <<= ICH_VMCR_BPR0_SHIFT;
> >> >> +  val &= ICH_VMCR_BPR0_MASK;
> >> >> +  vmcr &= ~ICH_VMCR_BPR0_MASK;
> >> >> +  vmcr |= val;
> >> >> +
> >> >> +  if (vmcr & ICH_VMCR_CBPR_MASK) {
> >> >> +          val = __vgic_v3_get_bpr1(vmcr);
> >> >> +          val <<= ICH_VMCR_BPR1_SHIFT;
> >> >> +          val &= ICH_VMCR_BPR1_MASK;
> >> >> +          vmcr &= ~ICH_VMCR_BPR1_MASK;
> >> >> +          vmcr |= val;
> >> >> +  }
> >> >
> >> > I don't understand why this block is needed?
> >>
> >> If you have CBPR already set, and then update BPR0, you need to make
> >> sure that BPR1 gets updated as well. You could hope that the HW would do
> >> it for you, but since we're erratum workaround land...
> >>
> >
> > I just didn't read the spec that way, I gathered that the hardware would
> > maintain read-as-written for for bpr1 but use bpr0 to set the binary
> > point when cbpr is set, and just ignore writes to bpr1 for as long as
> > cbpr is set.
> 
> This depends whether you're talking about the ICC/ICV BPR0/BPR1 registers,
> or the fields in the ICH_VMCR*. For the former, if CBPR is set then
> BPR1 reads and writes affect BPR0. 

>From the spec on ICV_BPR1_EL1: "Non-secure EL1 writes are ignored".
Doesn't that mean that reads of BPR1 reflect BPR0 but writes are
ignored?


> For the latter, the two fields
> are both independent and read-as-written regardless of the value
> of CBPR, it's just that the value in the BPR1 field has no effect.
> (The reason for this is for VM state migration: if a guest does:
>   - write X to BPR0
>   - write Y to BPR1
>   - set CBPR
>   - write Z to BPR0
>   - unset CBPR
>   - read BPR1
> it should get back Y still; so EL2 needs to have a way to see
> both the underlying BPR0 and BPR1 values even if CPBR is in effect.)
> 
> So the code above is not correct, I think, because it's making
> writes to BPR0 affect the BPR1 value. Instead what should happen
> is that when we emulate reads and writes to ICC_BPR1 we should pay
> attention to CBPR and work with either the VMCR BPR0 or BPR1 field
> appropriately.

I agree that we should drop the block above, but also think we should do
what we do in patch #5 and ignore writes to BPR1 if CBPR is set.

Thanks,
-Christoffer

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

* Re: [PATCH v2 13/25] KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler
  2017-06-06 17:23             ` Christoffer Dall
@ 2017-06-06 17:36               ` Peter Maydell
  -1 siblings, 0 replies; 152+ messages in thread
From: Peter Maydell @ 2017-06-06 17:36 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Marc Zyngier, kvm-devel, David Daney, Catalin Marinas,
	Robert Richter, arm-mail-list, kvmarm

On 6 June 2017 at 18:23, Christoffer Dall <cdall@linaro.org> wrote:
> On Tue, Jun 06, 2017 at 04:56:27PM +0100, Peter Maydell wrote:
>> This depends whether you're talking about the ICC/ICV BPR0/BPR1 registers,
>> or the fields in the ICH_VMCR*. For the former, if CBPR is set then
>> BPR1 reads and writes affect BPR0.
>
> From the spec on ICV_BPR1_EL1: "Non-secure EL1 writes are ignored".
> Doesn't that mean that reads of BPR1 reflect BPR0 but writes are
> ignored?

Yes, you're right.

thanks
-- PMM

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

* [PATCH v2 13/25] KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler
@ 2017-06-06 17:36               ` Peter Maydell
  0 siblings, 0 replies; 152+ messages in thread
From: Peter Maydell @ 2017-06-06 17:36 UTC (permalink / raw)
  To: linux-arm-kernel

On 6 June 2017 at 18:23, Christoffer Dall <cdall@linaro.org> wrote:
> On Tue, Jun 06, 2017 at 04:56:27PM +0100, Peter Maydell wrote:
>> This depends whether you're talking about the ICC/ICV BPR0/BPR1 registers,
>> or the fields in the ICH_VMCR*. For the former, if CBPR is set then
>> BPR1 reads and writes affect BPR0.
>
> From the spec on ICV_BPR1_EL1: "Non-secure EL1 writes are ignored".
> Doesn't that mean that reads of BPR1 reflect BPR0 but writes are
> ignored?

Yes, you're right.

thanks
-- PMM

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

* Re: [PATCH v2 00/25] arm64: KVM: Mediate access to GICv3 sysregs at EL2
  2017-06-01 10:20 ` Marc Zyngier
@ 2017-06-08 14:35   ` Alexander Graf
  -1 siblings, 0 replies; 152+ messages in thread
From: Alexander Graf @ 2017-06-08 14:35 UTC (permalink / raw)
  To: Marc Zyngier, Christoffer Dall
  Cc: kvm, David Daney, Catalin Marinas, Robert Richter, kvmarm,
	linux-arm-kernel



On 01.06.17 12:20, Marc Zyngier wrote:
> Some systems have less than perfect GICv3 implementations, leading to
> all kind of ugly issues (guest hanging, host dying). In order to allow
> some level of diagnostic, and in some cases implement workarounds,
> this series enables the trapping of both Group-0, Group-1 and Common
> sysregs. Mediating the access at EL2 allows some form of sanity
> checking that the HW is sometimes sorely lacking.
> 
> Instead of fully emulating a GICv3 CPU interface, we still use the
> existing HW (list registers, AP registers, VMCR...), which allows the
> code to be independent from the rest of the KVM code, and to cope with
> partial trapping.
> 
> Of course, trapping has a cost, which is why this must be either
> enabled on the command line, or selected by another cpu capability
> (see Cavium erratum 30115). A quick test on an A57-based platform
> shows a 25% hit when repeatedly banging on the trapped registers,
> while normal workloads do not seem to suffer noticeably from such
> trapping (hackbench variance is in the usual noise, despite being very
> IPI happy).
> 
> This has been tested on a dual socket Thundex-X and a Freescale LS-2085a.
> 
> I've taken the liberty to rebase David Daney's initial Cavium erratum
> 30115 workaround on top of this series, and included it here as a
> typical use case.

I've run this patch set on an affected ThunderX system and indeed not 
seen any hangs. I have seen lost guest USB keyboard events which might 
point at interrupt problems or not, but let's assume it's a different 
issue for now.

Tested-by: Alexander Graf <agraf@suse.de>


Alex

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

* [PATCH v2 00/25] arm64: KVM: Mediate access to GICv3 sysregs at EL2
@ 2017-06-08 14:35   ` Alexander Graf
  0 siblings, 0 replies; 152+ messages in thread
From: Alexander Graf @ 2017-06-08 14:35 UTC (permalink / raw)
  To: linux-arm-kernel



On 01.06.17 12:20, Marc Zyngier wrote:
> Some systems have less than perfect GICv3 implementations, leading to
> all kind of ugly issues (guest hanging, host dying). In order to allow
> some level of diagnostic, and in some cases implement workarounds,
> this series enables the trapping of both Group-0, Group-1 and Common
> sysregs. Mediating the access at EL2 allows some form of sanity
> checking that the HW is sometimes sorely lacking.
> 
> Instead of fully emulating a GICv3 CPU interface, we still use the
> existing HW (list registers, AP registers, VMCR...), which allows the
> code to be independent from the rest of the KVM code, and to cope with
> partial trapping.
> 
> Of course, trapping has a cost, which is why this must be either
> enabled on the command line, or selected by another cpu capability
> (see Cavium erratum 30115). A quick test on an A57-based platform
> shows a 25% hit when repeatedly banging on the trapped registers,
> while normal workloads do not seem to suffer noticeably from such
> trapping (hackbench variance is in the usual noise, despite being very
> IPI happy).
> 
> This has been tested on a dual socket Thundex-X and a Freescale LS-2085a.
> 
> I've taken the liberty to rebase David Daney's initial Cavium erratum
> 30115 workaround on top of this series, and included it here as a
> typical use case.

I've run this patch set on an affected ThunderX system and indeed not 
seen any hangs. I have seen lost guest USB keyboard events which might 
point at interrupt problems or not, but let's assume it's a different 
issue for now.

Tested-by: Alexander Graf <agraf@suse.de>


Alex

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

end of thread, other threads:[~2017-06-08 14:35 UTC | newest]

Thread overview: 152+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-01 10:20 [PATCH v2 00/25] arm64: KVM: Mediate access to GICv3 sysregs at EL2 Marc Zyngier
2017-06-01 10:20 ` Marc Zyngier
2017-06-01 10:20 ` [PATCH v2 01/25] arm64: Add a facility to turn an ESR syndrome into a sysreg encoding Marc Zyngier
2017-06-01 10:20   ` Marc Zyngier
2017-06-01 10:20 ` [PATCH v2 02/25] KVM: arm/arm64: vgic-v3: Add accessors for the ICH_APxRn_EL2 registers Marc Zyngier
2017-06-01 10:20   ` Marc Zyngier
2017-06-01 10:20 ` [PATCH v2 03/25] KVM: arm64: Make kvm_condition_valid32() accessible from EL2 Marc Zyngier
2017-06-01 10:20   ` Marc Zyngier
2017-06-04 12:11   ` Christoffer Dall
2017-06-04 12:11     ` Christoffer Dall
2017-06-05  8:13     ` Marc Zyngier
2017-06-05  8:13       ` Marc Zyngier
2017-06-05  8:23       ` Christoffer Dall
2017-06-05  8:23         ` Christoffer Dall
2017-06-05  9:10         ` Marc Zyngier
2017-06-05  9:10           ` Marc Zyngier
2017-06-01 10:20 ` [PATCH v2 04/25] KVM: arm64: vgic-v3: Add hook to handle guest GICv3 sysreg accesses at EL2 Marc Zyngier
2017-06-01 10:20   ` Marc Zyngier
2017-06-04 14:59   ` Christoffer Dall
2017-06-04 14:59     ` Christoffer Dall
2017-06-01 10:20 ` [PATCH v2 05/25] KVM: arm64: vgic-v3: Add ICV_BPR1_EL1 handler Marc Zyngier
2017-06-01 10:20   ` Marc Zyngier
2017-06-04 20:25   ` Christoffer Dall
2017-06-04 20:25     ` Christoffer Dall
2017-06-05  9:58     ` Marc Zyngier
2017-06-05  9:58       ` Marc Zyngier
2017-06-05 10:16       ` Christoffer Dall
2017-06-05 10:16         ` Christoffer Dall
2017-06-05 10:27         ` Peter Maydell
2017-06-05 10:27           ` Peter Maydell
2017-06-06  9:41       ` Christoffer Dall
2017-06-06  9:41         ` Christoffer Dall
2017-06-01 10:20 ` [PATCH v2 06/25] KVM: arm64: vgic-v3: Add ICV_IGRPEN1_EL1 handler Marc Zyngier
2017-06-01 10:20   ` Marc Zyngier
2017-06-06 13:22   ` Christoffer Dall
2017-06-06 13:22     ` Christoffer Dall
2017-06-01 10:20 ` [PATCH v2 07/25] KVM: arm64: vgic-v3: Add ICV_IAR1_EL1 handler Marc Zyngier
2017-06-01 10:20   ` Marc Zyngier
2017-06-05  9:21   ` Christoffer Dall
2017-06-05  9:21     ` Christoffer Dall
2017-06-05 10:33     ` Marc Zyngier
2017-06-05 10:33       ` Marc Zyngier
2017-06-06 11:09       ` Christoffer Dall
2017-06-06 11:09         ` Christoffer Dall
2017-06-06 13:35         ` Marc Zyngier
2017-06-06 13:35           ` Marc Zyngier
2017-06-06 13:50           ` Christoffer Dall
2017-06-06 13:50             ` Christoffer Dall
2017-06-01 10:21 ` [PATCH v2 08/25] KVM: arm64: vgic-v3: Add ICV_EOIR1_EL1 handler Marc Zyngier
2017-06-01 10:21   ` Marc Zyngier
2017-06-05 10:32   ` Christoffer Dall
2017-06-05 10:32     ` Christoffer Dall
2017-06-05 11:00     ` Marc Zyngier
2017-06-05 11:00       ` Marc Zyngier
2017-06-06 13:19       ` Christoffer Dall
2017-06-06 13:19         ` Christoffer Dall
2017-06-01 10:21 ` [PATCH v2 09/25] KVM: arm64: vgic-v3: Add ICV_AP1Rn_EL1 handler Marc Zyngier
2017-06-01 10:21   ` Marc Zyngier
2017-06-06 13:22   ` Christoffer Dall
2017-06-06 13:22     ` Christoffer Dall
2017-06-01 10:21 ` [PATCH v2 10/25] KVM: arm64: vgic-v3: Add ICV_HPPIR1_EL1 handler Marc Zyngier
2017-06-01 10:21   ` Marc Zyngier
2017-06-06 11:51   ` Christoffer Dall
2017-06-06 11:51     ` Christoffer Dall
2017-06-06 13:57     ` Marc Zyngier
2017-06-06 13:57       ` Marc Zyngier
2017-06-06 14:41       ` Christoffer Dall
2017-06-06 14:41         ` Christoffer Dall
2017-06-01 10:21 ` [PATCH v2 11/25] KVM: arm64: vgic-v3: Enable trapping of Group-1 system registers Marc Zyngier
2017-06-01 10:21   ` Marc Zyngier
2017-06-06 13:22   ` Christoffer Dall
2017-06-06 13:22     ` Christoffer Dall
2017-06-01 10:21 ` [PATCH v2 12/25] KVM: arm64: Enable GICv3 Group-1 sysreg trapping via command-line Marc Zyngier
2017-06-01 10:21   ` Marc Zyngier
2017-06-06 12:06   ` Christoffer Dall
2017-06-06 12:06     ` Christoffer Dall
2017-06-06 13:59     ` Marc Zyngier
2017-06-06 13:59       ` Marc Zyngier
2017-06-06 14:42       ` Christoffer Dall
2017-06-06 14:42         ` Christoffer Dall
2017-06-01 10:21 ` [PATCH v2 13/25] KVM: arm64: vgic-v3: Add ICV_BPR0_EL1 handler Marc Zyngier
2017-06-01 10:21   ` Marc Zyngier
2017-06-06 12:11   ` Christoffer Dall
2017-06-06 12:11     ` Christoffer Dall
2017-06-06 15:15     ` Marc Zyngier
2017-06-06 15:15       ` Marc Zyngier
2017-06-06 15:46       ` Christoffer Dall
2017-06-06 15:46         ` Christoffer Dall
2017-06-06 15:56         ` Peter Maydell
2017-06-06 15:56           ` Peter Maydell
2017-06-06 16:56           ` Marc Zyngier
2017-06-06 16:56             ` Marc Zyngier
2017-06-06 17:23           ` Christoffer Dall
2017-06-06 17:23             ` Christoffer Dall
2017-06-06 17:36             ` Peter Maydell
2017-06-06 17:36               ` Peter Maydell
2017-06-01 10:21 ` [PATCH v2 14/25] KVM: arm64: vgic-v3: Add ICV_IGNREN0_EL1 handler Marc Zyngier
2017-06-01 10:21   ` Marc Zyngier
2017-06-06 13:22   ` Christoffer Dall
2017-06-06 13:22     ` Christoffer Dall
2017-06-01 10:21 ` [PATCH v2 15/25] KVM: arm64: vgic-v3: Add misc Group-0 handlers Marc Zyngier
2017-06-01 10:21   ` Marc Zyngier
2017-06-06 13:22   ` Christoffer Dall
2017-06-06 13:22     ` Christoffer Dall
2017-06-01 10:21 ` [PATCH v2 16/25] KVM: arm64: vgic-v3: Enable trapping of Group-0 system registers Marc Zyngier
2017-06-01 10:21   ` Marc Zyngier
2017-06-06 13:22   ` Christoffer Dall
2017-06-06 13:22     ` Christoffer Dall
2017-06-01 10:21 ` [PATCH v2 17/25] KVM: arm64: Enable GICv3 Group-0 sysreg trapping via command-line Marc Zyngier
2017-06-01 10:21   ` Marc Zyngier
2017-06-06 12:44   ` Christoffer Dall
2017-06-06 12:44     ` Christoffer Dall
2017-06-06 15:15     ` Marc Zyngier
2017-06-06 15:15       ` Marc Zyngier
2017-06-01 10:21 ` [PATCH v2 18/25] arm64: Add MIDR values for Cavium cn83XX SoCs Marc Zyngier
2017-06-01 10:21   ` Marc Zyngier
2017-06-01 10:21 ` [PATCH v2 19/25] arm64: Add workaround for Cavium Thunder erratum 30115 Marc Zyngier
2017-06-01 10:21   ` Marc Zyngier
2017-06-06 12:48   ` Christoffer Dall
2017-06-06 12:48     ` Christoffer Dall
2017-06-06 15:18     ` Marc Zyngier
2017-06-06 15:18       ` Marc Zyngier
2017-06-01 10:21 ` [PATCH v2 20/25] KVM: arm64: vgic-v3: Add ICV_DIR_EL1 handler Marc Zyngier
2017-06-01 10:21   ` Marc Zyngier
2017-06-06 12:59   ` Christoffer Dall
2017-06-06 12:59     ` Christoffer Dall
2017-06-01 10:21 ` [PATCH v2 21/25] KVM: arm64: vgic-v3: Add ICV_RPR_EL1 handler Marc Zyngier
2017-06-01 10:21   ` Marc Zyngier
2017-06-06 13:23   ` Christoffer Dall
2017-06-06 13:23     ` Christoffer Dall
2017-06-01 10:21 ` [PATCH v2 22/25] KVM: arm64: vgic-v3: Add ICV_CTLR_EL1 handler Marc Zyngier
2017-06-01 10:21   ` Marc Zyngier
2017-06-06 13:23   ` Christoffer Dall
2017-06-06 13:23     ` Christoffer Dall
2017-06-01 10:21 ` [PATCH v2 23/25] KVM: arm64: vgic-v3: Add ICV_PMR_EL1 handler Marc Zyngier
2017-06-01 10:21   ` Marc Zyngier
2017-06-06 13:23   ` Christoffer Dall
2017-06-06 13:23     ` Christoffer Dall
2017-06-01 10:21 ` [PATCH v2 24/25] KVM: arm64: Enable GICv3 common sysreg trapping via command-line Marc Zyngier
2017-06-01 10:21   ` Marc Zyngier
2017-06-01 10:21 ` [PATCH v2 25/25] KVM: arm64: vgic-v3: Log which GICv3 system registers are trapped Marc Zyngier
2017-06-01 10:21   ` Marc Zyngier
2017-06-06 13:23   ` Christoffer Dall
2017-06-06 13:23     ` Christoffer Dall
2017-06-01 21:00 ` [PATCH v2 00/25] arm64: KVM: Mediate access to GICv3 sysregs at EL2 David Daney
2017-06-01 21:00   ` David Daney
2017-06-02  9:11   ` Marc Zyngier
2017-06-02  9:11     ` Marc Zyngier
2017-06-02 16:24     ` David Daney
2017-06-02 16:24       ` David Daney
2017-06-08 14:35 ` Alexander Graf
2017-06-08 14:35   ` Alexander Graf

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.