linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/14] KVM: arm/arm64: Various rework in preparation of nested virt support
@ 2019-01-24 14:00 Christoffer Dall
  2019-01-24 14:00 ` [PATCH 01/14] arm/arm64: KVM: Introduce kvm_call_hyp_ret() Christoffer Dall
                   ` (13 more replies)
  0 siblings, 14 replies; 33+ messages in thread
From: Christoffer Dall @ 2019-01-24 14:00 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, Christoffer Dall, kvm

This series contains a somewhat random set of reworks and improvements to the
KVM/Arm code in preparation for nested virtualization support.

We plan to merge these as early as v5.1.

The series relies on an additional patch which exposes the physical EL1 timer's
IRQ number to KVM:
  "clocksource/arm_arch_timer: Store physical timer IRQ number for KVM on VHE"
  https://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1908965.html


Andre Przywara (1):
  KVM: arm/arm64: consolidate arch timer trap handlers

Christoffer Dall (6):
  KVM: arm/arm64: Factor out VMID into struct kvm_vmid
  KVM: arm/arm64: Simplify bg_timer programming
  KVM: arm/arm64: timer: Rework data structures for multiple timers
  KVM: arm/arm64: arch_timer: Assign the phys timer on VHE systems
  KVM: arm/arm64: Rework the timer code to use a timer_map
  KVM: arm/arm64: Move kvm_is_write_fault to header file

Marc Zyngier (7):
  arm/arm64: KVM: Introduce kvm_call_hyp_ret()
  arm64: KVM: Allow for direct call of HYP functions when using VHE
  arm64: KVM: Drop VHE-specific HYP call stub
  ARM: KVM: Teach some form of type-safety to kvm_call_hyp
  arm/arm64: KVM: Statically configure the host's view of MPIDR
  KVM: arm64: Fix ICH_ELRSR_EL2 sysreg naming
  KVM: arm64: Reuse sys_reg() macro when searching the trap table

 arch/arm/include/asm/arch_gicv3.h    |   4 +-
 arch/arm/include/asm/kvm_emulate.h   |   8 +
 arch/arm/include/asm/kvm_host.h      |  53 ++-
 arch/arm/include/asm/kvm_hyp.h       |   4 +
 arch/arm/include/asm/kvm_mmu.h       |  11 +
 arch/arm/kvm/coproc.c                |  23 +-
 arch/arm/kvm/hyp/cp15-sr.c           |   1 -
 arch/arm/kvm/hyp/hyp-entry.S         |   2 +-
 arch/arm/kvm/hyp/switch.c            |   2 +-
 arch/arm/kvm/hyp/tlb.c               |   4 +-
 arch/arm/kvm/interrupts.S            |   4 +-
 arch/arm64/include/asm/kvm_emulate.h |   8 +
 arch/arm64/include/asm/kvm_host.h    |  48 ++-
 arch/arm64/include/asm/kvm_hyp.h     |   3 +-
 arch/arm64/include/asm/kvm_mmu.h     |  11 +
 arch/arm64/include/asm/sysreg.h      |   6 +-
 arch/arm64/kvm/debug.c               |   2 +-
 arch/arm64/kvm/hyp.S                 |   3 -
 arch/arm64/kvm/hyp/hyp-entry.S       |  12 -
 arch/arm64/kvm/hyp/sysreg-sr.c       |   1 -
 arch/arm64/kvm/sys_regs.c            |  99 +++--
 include/kvm/arm_arch_timer.h         |  68 +++-
 virt/kvm/arm/arch_timer.c            | 583 +++++++++++++++++++--------
 virt/kvm/arm/arm.c                   |  62 +--
 virt/kvm/arm/hyp/vgic-v3-sr.c        |   2 +-
 virt/kvm/arm/mmu.c                   |  10 +-
 virt/kvm/arm/trace.h                 | 105 +++++
 virt/kvm/arm/vgic/vgic-v3.c          |   4 +-
 28 files changed, 799 insertions(+), 344 deletions(-)

-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 01/14] arm/arm64: KVM: Introduce kvm_call_hyp_ret()
  2019-01-24 14:00 [PATCH 00/14] KVM: arm/arm64: Various rework in preparation of nested virt support Christoffer Dall
@ 2019-01-24 14:00 ` Christoffer Dall
  2019-01-24 14:00 ` [PATCH 02/14] arm64: KVM: Allow for direct call of HYP functions when using VHE Christoffer Dall
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 33+ messages in thread
From: Christoffer Dall @ 2019-01-24 14:00 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, kvm

From: Marc Zyngier <marc.zyngier@arm.com>

Until now, we haven't differentiated between HYP calls that
have a return value and those who don't. As we're about to
change this, introduce kvm_call_hyp_ret(), and change all
call sites that actually make use of a return value.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Christoffer Dall <christoffer.dall@arm.com>
---
 arch/arm/include/asm/kvm_host.h   | 3 +++
 arch/arm64/include/asm/kvm_host.h | 1 +
 arch/arm64/kvm/debug.c            | 2 +-
 virt/kvm/arm/arm.c                | 2 +-
 virt/kvm/arm/vgic/vgic-v3.c       | 4 ++--
 5 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index ca56537b61bc..023c9f2b1eea 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -214,7 +214,10 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
 int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
 int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
 int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
+
 unsigned long kvm_call_hyp(void *hypfn, ...);
+#define kvm_call_hyp_ret(f, ...) kvm_call_hyp(f, ##__VA_ARGS__)
+
 void force_vm_exit(const cpumask_t *mask);
 int __kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
 			      struct kvm_vcpu_events *events);
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 7732d0ba4e60..e54cb7c88a4e 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -371,6 +371,7 @@ void kvm_arm_resume_guest(struct kvm *kvm);
 
 u64 __kvm_call_hyp(void *hypfn, ...);
 #define kvm_call_hyp(f, ...) __kvm_call_hyp(kvm_ksym_ref(f), ##__VA_ARGS__)
+#define kvm_call_hyp_ret(f, ...) kvm_call_hyp(f, ##__VA_ARGS__)
 
 void force_vm_exit(const cpumask_t *mask);
 void kvm_mmu_wp_memory_region(struct kvm *kvm, int slot);
diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c
index f39801e4136c..fd917d6d12af 100644
--- a/arch/arm64/kvm/debug.c
+++ b/arch/arm64/kvm/debug.c
@@ -76,7 +76,7 @@ static void restore_guest_debug_regs(struct kvm_vcpu *vcpu)
 
 void kvm_arm_init_debug(void)
 {
-	__this_cpu_write(mdcr_el2, kvm_call_hyp(__kvm_get_mdcr_el2));
+	__this_cpu_write(mdcr_el2, kvm_call_hyp_ret(__kvm_get_mdcr_el2));
 }
 
 /**
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 9e350fd34504..4d55f98f97f7 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -765,7 +765,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 			ret = kvm_vcpu_run_vhe(vcpu);
 			kvm_arm_vhe_guest_exit();
 		} else {
-			ret = kvm_call_hyp(__kvm_vcpu_run_nvhe, vcpu);
+			ret = kvm_call_hyp_ret(__kvm_vcpu_run_nvhe, vcpu);
 		}
 
 		vcpu->mode = OUTSIDE_GUEST_MODE;
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 9c0dd234ebe8..67f98151c88d 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -589,7 +589,7 @@ early_param("kvm-arm.vgic_v4_enable", early_gicv4_enable);
  */
 int vgic_v3_probe(const struct gic_kvm_info *info)
 {
-	u32 ich_vtr_el2 = kvm_call_hyp(__vgic_v3_get_ich_vtr_el2);
+	u32 ich_vtr_el2 = kvm_call_hyp_ret(__vgic_v3_get_ich_vtr_el2);
 	int ret;
 
 	/*
@@ -679,7 +679,7 @@ void vgic_v3_put(struct kvm_vcpu *vcpu)
 	struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
 
 	if (likely(cpu_if->vgic_sre))
-		cpu_if->vgic_vmcr = kvm_call_hyp(__vgic_v3_read_vmcr);
+		cpu_if->vgic_vmcr = kvm_call_hyp_ret(__vgic_v3_read_vmcr);
 
 	kvm_call_hyp(__vgic_v3_save_aprs, vcpu);
 
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 02/14] arm64: KVM: Allow for direct call of HYP functions when using VHE
  2019-01-24 14:00 [PATCH 00/14] KVM: arm/arm64: Various rework in preparation of nested virt support Christoffer Dall
  2019-01-24 14:00 ` [PATCH 01/14] arm/arm64: KVM: Introduce kvm_call_hyp_ret() Christoffer Dall
@ 2019-01-24 14:00 ` Christoffer Dall
  2019-01-24 14:00 ` [PATCH 03/14] arm64: KVM: Drop VHE-specific HYP call stub Christoffer Dall
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 33+ messages in thread
From: Christoffer Dall @ 2019-01-24 14:00 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, kvm

From: Marc Zyngier <marc.zyngier@arm.com>

When running VHE, there is no need to jump via some stub to perform
a "HYP" function call, as there is a single address space.

Let's thus change kvm_call_hyp() and co to perform a direct call
in this case. Although this results in a bit of code expansion,
it allows the compiler to check for type compatibility, something
that we are missing so far.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Christoffer Dall <christoffer.dall@arm.com>
---
 arch/arm64/include/asm/kvm_host.h | 32 +++++++++++++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index e54cb7c88a4e..8b7702bdb219 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -370,8 +370,36 @@ void kvm_arm_halt_guest(struct kvm *kvm);
 void kvm_arm_resume_guest(struct kvm *kvm);
 
 u64 __kvm_call_hyp(void *hypfn, ...);
-#define kvm_call_hyp(f, ...) __kvm_call_hyp(kvm_ksym_ref(f), ##__VA_ARGS__)
-#define kvm_call_hyp_ret(f, ...) kvm_call_hyp(f, ##__VA_ARGS__)
+
+/*
+ * The couple of isb() below are there to guarantee the same behaviour
+ * on VHE as on !VHE, where the eret to EL1 acts as a context
+ * synchronization event.
+ */
+#define kvm_call_hyp(f, ...)						\
+	do {								\
+		if (has_vhe()) {					\
+			f(__VA_ARGS__);					\
+			isb();						\
+		} else {						\
+			__kvm_call_hyp(kvm_ksym_ref(f), ##__VA_ARGS__); \
+		}							\
+	} while(0)
+
+#define kvm_call_hyp_ret(f, ...)					\
+	({								\
+		typeof(f(__VA_ARGS__)) ret;				\
+									\
+		if (has_vhe()) {					\
+			ret = f(__VA_ARGS__);				\
+			isb();						\
+		} else {						\
+			ret = __kvm_call_hyp(kvm_ksym_ref(f),		\
+					     ##__VA_ARGS__);		\
+		}							\
+									\
+		ret;							\
+	})
 
 void force_vm_exit(const cpumask_t *mask);
 void kvm_mmu_wp_memory_region(struct kvm *kvm, int slot);
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 03/14] arm64: KVM: Drop VHE-specific HYP call stub
  2019-01-24 14:00 [PATCH 00/14] KVM: arm/arm64: Various rework in preparation of nested virt support Christoffer Dall
  2019-01-24 14:00 ` [PATCH 01/14] arm/arm64: KVM: Introduce kvm_call_hyp_ret() Christoffer Dall
  2019-01-24 14:00 ` [PATCH 02/14] arm64: KVM: Allow for direct call of HYP functions when using VHE Christoffer Dall
@ 2019-01-24 14:00 ` Christoffer Dall
  2019-01-24 14:00 ` [PATCH 04/14] ARM: KVM: Teach some form of type-safety to kvm_call_hyp Christoffer Dall
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 33+ messages in thread
From: Christoffer Dall @ 2019-01-24 14:00 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, kvm

From: Marc Zyngier <marc.zyngier@arm.com>

We now call VHE code directly, without going through any central
dispatching function. Let's drop that code.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Christoffer Dall <christoffer.dall@arm.com>
---
 arch/arm64/kvm/hyp.S           |  3 ---
 arch/arm64/kvm/hyp/hyp-entry.S | 12 ------------
 2 files changed, 15 deletions(-)

diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S
index 952f6cb9cf72..2845aa680841 100644
--- a/arch/arm64/kvm/hyp.S
+++ b/arch/arm64/kvm/hyp.S
@@ -40,9 +40,6 @@
  * arch/arm64/kernel/hyp_stub.S.
  */
 ENTRY(__kvm_call_hyp)
-alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
 	hvc	#0
 	ret
-alternative_else_nop_endif
-	b	__vhe_hyp_call
 ENDPROC(__kvm_call_hyp)
diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
index 73c1b483ec39..2b1e686772bf 100644
--- a/arch/arm64/kvm/hyp/hyp-entry.S
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -43,18 +43,6 @@
 	ldr	lr, [sp], #16
 .endm
 
-ENTRY(__vhe_hyp_call)
-	do_el2_call
-	/*
-	 * We used to rely on having an exception return to get
-	 * an implicit isb. In the E2H case, we don't have it anymore.
-	 * rather than changing all the leaf functions, just do it here
-	 * before returning to the rest of the kernel.
-	 */
-	isb
-	ret
-ENDPROC(__vhe_hyp_call)
-
 el1_sync:				// Guest trapped into EL2
 
 	mrs	x0, esr_el2
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 04/14] ARM: KVM: Teach some form of type-safety to kvm_call_hyp
  2019-01-24 14:00 [PATCH 00/14] KVM: arm/arm64: Various rework in preparation of nested virt support Christoffer Dall
                   ` (2 preceding siblings ...)
  2019-01-24 14:00 ` [PATCH 03/14] arm64: KVM: Drop VHE-specific HYP call stub Christoffer Dall
@ 2019-01-24 14:00 ` Christoffer Dall
  2019-01-24 14:00 ` [PATCH 05/14] arm/arm64: KVM: Statically configure the host's view of MPIDR Christoffer Dall
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 33+ messages in thread
From: Christoffer Dall @ 2019-01-24 14:00 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, kvm

From: Marc Zyngier <marc.zyngier@arm.com>

Just like on arm64, and for the same reasons, kvm_call_hyp removes
any form of type safety when calling into HYP. But we can still
try to tell the compiler what we're trying to achieve.

Here, we can add code that would do the function call if it wasn't
guarded by an always-false predicate. Hopefully, the compiler is
dumb enough to do the type checking and clever enough to not emit
the corresponding code...

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Christoffer Dall <christoffer.dall@arm.com>
---
 arch/arm/include/asm/kvm_host.h | 31 ++++++++++++++++++++++++++++---
 arch/arm/kvm/hyp/hyp-entry.S    |  2 +-
 arch/arm/kvm/interrupts.S       |  4 ++--
 3 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 023c9f2b1eea..4b6193f2f0f6 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -215,8 +215,33 @@ int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
 int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
 int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
 
-unsigned long kvm_call_hyp(void *hypfn, ...);
-#define kvm_call_hyp_ret(f, ...) kvm_call_hyp(f, ##__VA_ARGS__)
+unsigned long __kvm_call_hyp(void *hypfn, ...);
+
+/*
+ * The has_vhe() part doesn't get emitted, but is used for type-checking.
+ */
+#define kvm_call_hyp(f, ...)						\
+	do {								\
+		if (has_vhe()) {					\
+			f(__VA_ARGS__);					\
+		} else {						\
+			__kvm_call_hyp(kvm_ksym_ref(f), ##__VA_ARGS__); \
+		}							\
+	} while(0)
+
+#define kvm_call_hyp_ret(f, ...)					\
+	({								\
+		typeof(f(__VA_ARGS__)) ret;				\
+									\
+		if (has_vhe()) {					\
+			ret = f(__VA_ARGS__);				\
+		} else {						\
+			ret = __kvm_call_hyp(kvm_ksym_ref(f),		\
+					     ##__VA_ARGS__);		\
+		}							\
+									\
+		ret;							\
+	})
 
 void force_vm_exit(const cpumask_t *mask);
 int __kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
@@ -268,7 +293,7 @@ static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
 	 * compliant with the PCS!).
 	 */
 
-	kvm_call_hyp((void*)hyp_stack_ptr, vector_ptr, pgd_ptr);
+	__kvm_call_hyp((void*)hyp_stack_ptr, vector_ptr, pgd_ptr);
 }
 
 static inline void __cpu_init_stage2(void)
diff --git a/arch/arm/kvm/hyp/hyp-entry.S b/arch/arm/kvm/hyp/hyp-entry.S
index aa3f9a9837ac..6ed3cf23fe89 100644
--- a/arch/arm/kvm/hyp/hyp-entry.S
+++ b/arch/arm/kvm/hyp/hyp-entry.S
@@ -176,7 +176,7 @@ THUMB(	orr	lr, lr, #PSR_T_BIT	)
 	msr	spsr_cxsf, lr
 	ldr	lr, =panic
 	msr	ELR_hyp, lr
-	ldr	lr, =kvm_call_hyp
+	ldr	lr, =__kvm_call_hyp
 	clrex
 	eret
 ENDPROC(__hyp_do_panic)
diff --git a/arch/arm/kvm/interrupts.S b/arch/arm/kvm/interrupts.S
index 80a1d6cd261c..a08e6419ebe9 100644
--- a/arch/arm/kvm/interrupts.S
+++ b/arch/arm/kvm/interrupts.S
@@ -42,7 +42,7 @@
  *   r12:     caller save
  *   rest:    callee save
  */
-ENTRY(kvm_call_hyp)
+ENTRY(__kvm_call_hyp)
 	hvc	#0
 	bx	lr
-ENDPROC(kvm_call_hyp)
+ENDPROC(__kvm_call_hyp)
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 05/14] arm/arm64: KVM: Statically configure the host's view of MPIDR
  2019-01-24 14:00 [PATCH 00/14] KVM: arm/arm64: Various rework in preparation of nested virt support Christoffer Dall
                   ` (3 preceding siblings ...)
  2019-01-24 14:00 ` [PATCH 04/14] ARM: KVM: Teach some form of type-safety to kvm_call_hyp Christoffer Dall
@ 2019-01-24 14:00 ` Christoffer Dall
  2019-01-24 14:00 ` [PATCH 06/14] KVM: arm/arm64: Factor out VMID into struct kvm_vmid Christoffer Dall
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 33+ messages in thread
From: Christoffer Dall @ 2019-01-24 14:00 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, kvm

From: Marc Zyngier <marc.zyngier@arm.com>

We currently eagerly save/restore MPIDR. It turns out to be
slightly pointless:
- On the host, this value is known as soon as we're scheduled on a
  physical CPU
- In the guest, this value cannot change, as it is set by KVM
  (and this is a read-only register)

The result of the above is that we can perfectly avoid the eager
saving of MPIDR_EL1, and only keep the restore. We just have
to setup the host contexts appropriately at boot time.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Christoffer Dall <christoffer.dall@arm.com>
---
 arch/arm/include/asm/kvm_host.h   | 8 ++++++++
 arch/arm/kvm/hyp/cp15-sr.c        | 1 -
 arch/arm64/include/asm/kvm_host.h | 8 ++++++++
 arch/arm64/kvm/hyp/sysreg-sr.c    | 1 -
 virt/kvm/arm/arm.c                | 1 +
 5 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 4b6193f2f0f6..43e343e00fb8 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -26,6 +26,7 @@
 #include <asm/kvm_asm.h>
 #include <asm/kvm_mmio.h>
 #include <asm/fpstate.h>
+#include <asm/smp_plat.h>
 #include <kvm/arm_arch_timer.h>
 
 #define __KVM_HAVE_ARCH_INTC_INITIALIZED
@@ -147,6 +148,13 @@ struct kvm_cpu_context {
 
 typedef struct kvm_cpu_context kvm_cpu_context_t;
 
+static inline void kvm_init_host_cpu_context(kvm_cpu_context_t *cpu_ctxt,
+					     int cpu)
+{
+	/* The host's MPIDR is immutable, so let's set it up at boot time */
+	cpu_ctxt->cp15[c0_MPIDR] = cpu_logical_map(cpu);
+}
+
 struct kvm_vcpu_arch {
 	struct kvm_cpu_context ctxt;
 
diff --git a/arch/arm/kvm/hyp/cp15-sr.c b/arch/arm/kvm/hyp/cp15-sr.c
index c4782812714c..8bf895ec6e04 100644
--- a/arch/arm/kvm/hyp/cp15-sr.c
+++ b/arch/arm/kvm/hyp/cp15-sr.c
@@ -27,7 +27,6 @@ static u64 *cp15_64(struct kvm_cpu_context *ctxt, int idx)
 
 void __hyp_text __sysreg_save_state(struct kvm_cpu_context *ctxt)
 {
-	ctxt->cp15[c0_MPIDR]		= read_sysreg(VMPIDR);
 	ctxt->cp15[c0_CSSELR]		= read_sysreg(CSSELR);
 	ctxt->cp15[c1_SCTLR]		= read_sysreg(SCTLR);
 	ctxt->cp15[c1_CPACR]		= read_sysreg(CPACR);
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 8b7702bdb219..f497bb31031f 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -30,6 +30,7 @@
 #include <asm/kvm.h>
 #include <asm/kvm_asm.h>
 #include <asm/kvm_mmio.h>
+#include <asm/smp_plat.h>
 #include <asm/thread_info.h>
 
 #define __KVM_HAVE_ARCH_INTC_INITIALIZED
@@ -418,6 +419,13 @@ struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
 
 DECLARE_PER_CPU(kvm_cpu_context_t, kvm_host_cpu_state);
 
+static inline void kvm_init_host_cpu_context(kvm_cpu_context_t *cpu_ctxt,
+					     int cpu)
+{
+	/* The host's MPIDR is immutable, so let's set it up at boot time */
+	cpu_ctxt->sys_regs[MPIDR_EL1] = cpu_logical_map(cpu);
+}
+
 void __kvm_enable_ssbs(void);
 
 static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr,
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index 68d6f7c3b237..2498f86defcb 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -52,7 +52,6 @@ static void __hyp_text __sysreg_save_user_state(struct kvm_cpu_context *ctxt)
 
 static void __hyp_text __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
 {
-	ctxt->sys_regs[MPIDR_EL1]	= read_sysreg(vmpidr_el2);
 	ctxt->sys_regs[CSSELR_EL1]	= read_sysreg(csselr_el1);
 	ctxt->sys_regs[SCTLR_EL1]	= read_sysreg_el1(sctlr);
 	ctxt->sys_regs[ACTLR_EL1]	= read_sysreg(actlr_el1);
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 4d55f98f97f7..3dd240ea9e76 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -1561,6 +1561,7 @@ static int init_hyp_mode(void)
 		kvm_cpu_context_t *cpu_ctxt;
 
 		cpu_ctxt = per_cpu_ptr(&kvm_host_cpu_state, cpu);
+		kvm_init_host_cpu_context(cpu_ctxt, cpu);
 		err = create_hyp_mappings(cpu_ctxt, cpu_ctxt + 1, PAGE_HYP);
 
 		if (err) {
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 06/14] KVM: arm/arm64: Factor out VMID into struct kvm_vmid
  2019-01-24 14:00 [PATCH 00/14] KVM: arm/arm64: Various rework in preparation of nested virt support Christoffer Dall
                   ` (4 preceding siblings ...)
  2019-01-24 14:00 ` [PATCH 05/14] arm/arm64: KVM: Statically configure the host's view of MPIDR Christoffer Dall
@ 2019-01-24 14:00 ` Christoffer Dall
  2019-01-24 19:01   ` James Morse
                     ` (2 more replies)
  2019-01-24 14:00 ` [PATCH 07/14] KVM: arm/arm64: Simplify bg_timer programming Christoffer Dall
                   ` (7 subsequent siblings)
  13 siblings, 3 replies; 33+ messages in thread
From: Christoffer Dall @ 2019-01-24 14:00 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, Christoffer Dall, kvm

In preparation for nested virtualization where we are going to have more
than a single VMID per VM, let's factor out the VMID data into a
separate VMID data structure and change the VMID allocator to operate on
this new structure instead of using a struct kvm.

This also means that udate_vttbr now becomes update_vmid, and that the
vttbr itself is generated on the fly based on the stage 2 page table
base address and the vmid.

We cache the physical address of the pgd when allocating the pgd to
avoid doing the calculation on every entry to the guest and to avoid
calling into potentially non-hyp-mapped code from hyp/EL2.

If we wanted to merge the VMID allocator with the arm64 ASID allocator
at some point in the future, it should actually become easier to do that
after this patch.

Note that to avoid mapping the kvm_vmid_bits variable into hyp, we
simply forego the masking of the vmid value in kvm_get_vttbr and rely on
update_vmid to always assign a valid vmid value (within the supported
range).

Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/include/asm/kvm_host.h   | 13 ++++---
 arch/arm/include/asm/kvm_mmu.h    | 11 ++++++
 arch/arm/kvm/hyp/switch.c         |  2 +-
 arch/arm/kvm/hyp/tlb.c            |  4 +--
 arch/arm64/include/asm/kvm_host.h |  9 +++--
 arch/arm64/include/asm/kvm_hyp.h  |  3 +-
 arch/arm64/include/asm/kvm_mmu.h  | 11 ++++++
 virt/kvm/arm/arm.c                | 57 +++++++++++--------------------
 virt/kvm/arm/mmu.c                |  2 ++
 9 files changed, 63 insertions(+), 49 deletions(-)

diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 43e343e00fb8..8073267dc4a0 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -57,10 +57,13 @@ int __attribute_const__ kvm_target_cpu(void);
 int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
 void kvm_reset_coprocs(struct kvm_vcpu *vcpu);
 
-struct kvm_arch {
-	/* VTTBR value associated with below pgd and vmid */
-	u64    vttbr;
+struct kvm_vmid {
+	/* The VMID generation used for the virt. memory system */
+	u64    vmid_gen;
+	u32    vmid;
+};
 
+struct kvm_arch {
 	/* The last vcpu id that ran on each physical CPU */
 	int __percpu *last_vcpu_ran;
 
@@ -70,11 +73,11 @@ struct kvm_arch {
 	 */
 
 	/* The VMID generation used for the virt. memory system */
-	u64    vmid_gen;
-	u32    vmid;
+	struct kvm_vmid vmid;
 
 	/* Stage-2 page table */
 	pgd_t *pgd;
+	phys_addr_t pgd_phys;
 
 	/* Interrupt controller */
 	struct vgic_dist	vgic;
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index 3a875fc1b63c..fadbd9ad3a90 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -426,6 +426,17 @@ static inline bool kvm_cpu_has_cnp(void)
 	return false;
 }
 
+static __always_inline u64 kvm_get_vttbr(struct kvm *kvm)
+{
+	struct kvm_vmid *vmid = &kvm->arch.vmid;
+	u64 vmid_field, baddr;
+	u64 cnp = kvm_cpu_has_cnp() ? VTTBR_CNP_BIT : 0;
+
+	baddr = kvm->arch.pgd_phys;
+	vmid_field = (u64)vmid->vmid << VTTBR_VMID_SHIFT;
+	return kvm_phys_to_vttbr(baddr) | vmid_field | cnp;
+}
+
 #endif	/* !__ASSEMBLY__ */
 
 #endif /* __ARM_KVM_MMU_H__ */
diff --git a/arch/arm/kvm/hyp/switch.c b/arch/arm/kvm/hyp/switch.c
index acf1c37fa49c..3b058a5d7c5f 100644
--- a/arch/arm/kvm/hyp/switch.c
+++ b/arch/arm/kvm/hyp/switch.c
@@ -77,7 +77,7 @@ static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
 static void __hyp_text __activate_vm(struct kvm_vcpu *vcpu)
 {
 	struct kvm *kvm = kern_hyp_va(vcpu->kvm);
-	write_sysreg(kvm->arch.vttbr, VTTBR);
+	write_sysreg(kvm_get_vttbr(kvm), VTTBR);
 	write_sysreg(vcpu->arch.midr, VPIDR);
 }
 
diff --git a/arch/arm/kvm/hyp/tlb.c b/arch/arm/kvm/hyp/tlb.c
index c0edd450e104..8e4afba73635 100644
--- a/arch/arm/kvm/hyp/tlb.c
+++ b/arch/arm/kvm/hyp/tlb.c
@@ -41,7 +41,7 @@ void __hyp_text __kvm_tlb_flush_vmid(struct kvm *kvm)
 
 	/* Switch to requested VMID */
 	kvm = kern_hyp_va(kvm);
-	write_sysreg(kvm->arch.vttbr, VTTBR);
+	write_sysreg(kvm_get_vttbr(kvm), VTTBR);
 	isb();
 
 	write_sysreg(0, TLBIALLIS);
@@ -61,7 +61,7 @@ void __hyp_text __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu)
 	struct kvm *kvm = kern_hyp_va(kern_hyp_va(vcpu)->kvm);
 
 	/* Switch to requested VMID */
-	write_sysreg(kvm->arch.vttbr, VTTBR);
+	write_sysreg(kvm_get_vttbr(kvm), VTTBR);
 	isb();
 
 	write_sysreg(0, TLBIALL);
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index f497bb31031f..444dd1cb1958 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -57,16 +57,19 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
 int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext);
 void __extended_idmap_trampoline(phys_addr_t boot_pgd, phys_addr_t idmap_start);
 
-struct kvm_arch {
+struct kvm_vmid {
 	/* The VMID generation used for the virt. memory system */
 	u64    vmid_gen;
 	u32    vmid;
+};
+
+struct kvm_arch {
+	struct kvm_vmid vmid;
 
 	/* stage2 entry level table */
 	pgd_t *pgd;
+	phys_addr_t pgd_phys;
 
-	/* VTTBR value associated with above pgd and vmid */
-	u64    vttbr;
 	/* VTCR_EL2 value for this VM */
 	u64    vtcr;
 
diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
index a80a7ef57325..4da765f2cca5 100644
--- a/arch/arm64/include/asm/kvm_hyp.h
+++ b/arch/arm64/include/asm/kvm_hyp.h
@@ -21,6 +21,7 @@
 #include <linux/compiler.h>
 #include <linux/kvm_host.h>
 #include <asm/alternative.h>
+#include <asm/kvm_mmu.h>
 #include <asm/sysreg.h>
 
 #define __hyp_text __section(.hyp.text) notrace
@@ -163,7 +164,7 @@ void __noreturn __hyp_do_panic(unsigned long, ...);
 static __always_inline void __hyp_text __load_guest_stage2(struct kvm *kvm)
 {
 	write_sysreg(kvm->arch.vtcr, vtcr_el2);
-	write_sysreg(kvm->arch.vttbr, vttbr_el2);
+	write_sysreg(kvm_get_vttbr(kvm), vttbr_el2);
 
 	/*
 	 * ARM erratum 1165522 requires the actual execution of the above
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 8af4b1befa42..189d93461d33 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -596,5 +596,16 @@ static inline bool kvm_cpu_has_cnp(void)
 	return system_supports_cnp();
 }
 
+static __always_inline u64 kvm_get_vttbr(struct kvm *kvm)
+{
+	struct kvm_vmid *vmid = &kvm->arch.vmid;
+	u64 vmid_field, baddr;
+	u64 cnp = kvm_cpu_has_cnp() ? VTTBR_CNP_BIT : 0;
+
+	baddr = kvm->arch.pgd_phys;
+	vmid_field = (u64)vmid->vmid << VTTBR_VMID_SHIFT;
+	return kvm_phys_to_vttbr(baddr) | vmid_field | cnp;
+}
+
 #endif /* __ASSEMBLY__ */
 #endif /* __ARM64_KVM_MMU_H__ */
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 3dd240ea9e76..b77db673bb03 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -65,7 +65,6 @@ static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_arm_running_vcpu);
 /* The VMID used in the VTTBR */
 static atomic64_t kvm_vmid_gen = ATOMIC64_INIT(1);
 static u32 kvm_next_vmid;
-static unsigned int kvm_vmid_bits __read_mostly;
 static DEFINE_SPINLOCK(kvm_vmid_lock);
 
 static bool vgic_present;
@@ -142,7 +141,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 	kvm_vgic_early_init(kvm);
 
 	/* Mark the initial VMID generation invalid */
-	kvm->arch.vmid_gen = 0;
+	kvm->arch.vmid.vmid_gen = 0;
 
 	/* The maximum number of VCPUs is limited by the host's GIC model */
 	kvm->arch.max_vcpus = vgic_present ?
@@ -472,37 +471,31 @@ void force_vm_exit(const cpumask_t *mask)
 
 /**
  * need_new_vmid_gen - check that the VMID is still valid
- * @kvm: The VM's VMID to check
+ * @vmid: The VMID to check
  *
  * return true if there is a new generation of VMIDs being used
  *
- * The hardware supports only 256 values with the value zero reserved for the
- * host, so we check if an assigned value belongs to a previous generation,
- * which which requires us to assign a new value. If we're the first to use a
- * VMID for the new generation, we must flush necessary caches and TLBs on all
- * CPUs.
+ * The hardware supports a limited set of values with the value zero reserved
+ * for the host, so we check if an assigned value belongs to a previous
+ * generation, which which requires us to assign a new value. If we're the
+ * first to use a VMID for the new generation, we must flush necessary caches
+ * and TLBs on all CPUs.
  */
-static bool need_new_vmid_gen(struct kvm *kvm)
+static bool need_new_vmid_gen(struct kvm_vmid *vmid)
 {
 	u64 current_vmid_gen = atomic64_read(&kvm_vmid_gen);
 	smp_rmb(); /* Orders read of kvm_vmid_gen and kvm->arch.vmid */
-	return unlikely(READ_ONCE(kvm->arch.vmid_gen) != current_vmid_gen);
+	return unlikely(READ_ONCE(vmid->vmid_gen) != current_vmid_gen);
 }
 
 /**
- * update_vttbr - Update the VTTBR with a valid VMID before the guest runs
- * @kvm	The guest that we are about to run
- *
- * Called from kvm_arch_vcpu_ioctl_run before entering the guest to ensure the
- * VM has a valid VMID, otherwise assigns a new one and flushes corresponding
- * caches and TLBs.
+ * update_vmid - Update the vmid with a valid VMID for the current generation
+ * @kvm: The guest that struct vmid belongs to
+ * @vmid: The stage-2 VMID information struct
  */
-static void update_vttbr(struct kvm *kvm)
+static void update_vmid(struct kvm_vmid *vmid)
 {
-	phys_addr_t pgd_phys;
-	u64 vmid, cnp = kvm_cpu_has_cnp() ? VTTBR_CNP_BIT : 0;
-
-	if (!need_new_vmid_gen(kvm))
+	if (!need_new_vmid_gen(vmid))
 		return;
 
 	spin_lock(&kvm_vmid_lock);
@@ -512,7 +505,7 @@ static void update_vttbr(struct kvm *kvm)
 	 * already allocated a valid vmid for this vm, then this vcpu should
 	 * use the same vmid.
 	 */
-	if (!need_new_vmid_gen(kvm)) {
+	if (!need_new_vmid_gen(vmid)) {
 		spin_unlock(&kvm_vmid_lock);
 		return;
 	}
@@ -536,18 +529,12 @@ static void update_vttbr(struct kvm *kvm)
 		kvm_call_hyp(__kvm_flush_vm_context);
 	}
 
-	kvm->arch.vmid = kvm_next_vmid;
+	vmid->vmid = kvm_next_vmid;
 	kvm_next_vmid++;
-	kvm_next_vmid &= (1 << kvm_vmid_bits) - 1;
-
-	/* update vttbr to be used with the new vmid */
-	pgd_phys = virt_to_phys(kvm->arch.pgd);
-	BUG_ON(pgd_phys & ~kvm_vttbr_baddr_mask(kvm));
-	vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & VTTBR_VMID_MASK(kvm_vmid_bits);
-	kvm->arch.vttbr = kvm_phys_to_vttbr(pgd_phys) | vmid | cnp;
+	kvm_next_vmid &= (1 << kvm_get_vmid_bits()) - 1;
 
 	smp_wmb();
-	WRITE_ONCE(kvm->arch.vmid_gen, atomic64_read(&kvm_vmid_gen));
+	WRITE_ONCE(vmid->vmid_gen, atomic64_read(&kvm_vmid_gen));
 
 	spin_unlock(&kvm_vmid_lock);
 }
@@ -690,7 +677,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		 */
 		cond_resched();
 
-		update_vttbr(vcpu->kvm);
+		update_vmid(&vcpu->kvm->arch.vmid);
 
 		check_vcpu_requests(vcpu);
 
@@ -739,7 +726,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		 */
 		smp_store_mb(vcpu->mode, IN_GUEST_MODE);
 
-		if (ret <= 0 || need_new_vmid_gen(vcpu->kvm) ||
+		if (ret <= 0 || need_new_vmid_gen(&vcpu->kvm->arch.vmid) ||
 		    kvm_request_pending(vcpu)) {
 			vcpu->mode = OUTSIDE_GUEST_MODE;
 			isb(); /* Ensure work in x_flush_hwstate is committed */
@@ -1417,10 +1404,6 @@ static inline void hyp_cpu_pm_exit(void)
 
 static int init_common_resources(void)
 {
-	/* set size of VMID supported by CPU */
-	kvm_vmid_bits = kvm_get_vmid_bits();
-	kvm_info("%d-bit VMID\n", kvm_vmid_bits);
-
 	kvm_set_ipa_limit();
 
 	return 0;
diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
index fbdf3ac2f001..bffcbc423f4c 100644
--- a/virt/kvm/arm/mmu.c
+++ b/virt/kvm/arm/mmu.c
@@ -921,6 +921,7 @@ int kvm_alloc_stage2_pgd(struct kvm *kvm)
 		return -ENOMEM;
 
 	kvm->arch.pgd = pgd;
+	kvm->arch.pgd_phys = virt_to_phys(pgd);
 	return 0;
 }
 
@@ -1008,6 +1009,7 @@ void kvm_free_stage2_pgd(struct kvm *kvm)
 		unmap_stage2_range(kvm, 0, kvm_phys_size(kvm));
 		pgd = READ_ONCE(kvm->arch.pgd);
 		kvm->arch.pgd = NULL;
+		kvm->arch.pgd_phys = 0;
 	}
 	spin_unlock(&kvm->mmu_lock);
 
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 07/14] KVM: arm/arm64: Simplify bg_timer programming
  2019-01-24 14:00 [PATCH 00/14] KVM: arm/arm64: Various rework in preparation of nested virt support Christoffer Dall
                   ` (5 preceding siblings ...)
  2019-01-24 14:00 ` [PATCH 06/14] KVM: arm/arm64: Factor out VMID into struct kvm_vmid Christoffer Dall
@ 2019-01-24 14:00 ` Christoffer Dall
  2019-01-24 14:00 ` [PATCH 08/14] KVM: arm64: Fix ICH_ELRSR_EL2 sysreg naming Christoffer Dall
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 33+ messages in thread
From: Christoffer Dall @ 2019-01-24 14:00 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, Christoffer Dall, kvm

Instead of calling into kvm_timer_[un]schedule from the main kvm
blocking path, test if the VCPU is on the wait queue from the load/put
path and perform the background timer setup/cancel in this path.

This has the distinct advantage that we no longer race between load/put
and schedule/unschedule and programming and canceling of the bg_timer
always happens when the timer state is not loaded.

Note that we must now remove the checks in kvm_timer_blocking that do
not schedule a background timer if one of the timers can fire, because
we no longer have a guarantee that kvm_vcpu_check_block() will be called
before kvm_timer_blocking.

Reported-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/kvm/arm_arch_timer.h |  3 ---
 virt/kvm/arm/arch_timer.c    | 35 ++++++++++++++---------------------
 virt/kvm/arm/arm.c           |  2 --
 3 files changed, 14 insertions(+), 26 deletions(-)

diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index 33771352dcd6..d6e6a45d1d24 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -76,9 +76,6 @@ int kvm_arm_timer_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
 
 bool kvm_timer_is_pending(struct kvm_vcpu *vcpu);
 
-void kvm_timer_schedule(struct kvm_vcpu *vcpu);
-void kvm_timer_unschedule(struct kvm_vcpu *vcpu);
-
 u64 kvm_phys_timer_read(void);
 
 void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu);
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index b07ac4614e1c..4986028d9829 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -349,22 +349,12 @@ static void vtimer_save_state(struct kvm_vcpu *vcpu)
  * thread is removed from its waitqueue and made runnable when there's a timer
  * interrupt to handle.
  */
-void kvm_timer_schedule(struct kvm_vcpu *vcpu)
+static void kvm_timer_blocking(struct kvm_vcpu *vcpu)
 {
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
 	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
 
-	vtimer_save_state(vcpu);
-
-	/*
-	 * No need to schedule a background timer if any guest timer has
-	 * already expired, because kvm_vcpu_block will return before putting
-	 * the thread to sleep.
-	 */
-	if (kvm_timer_should_fire(vtimer) || kvm_timer_should_fire(ptimer))
-		return;
-
 	/*
 	 * If both timers are not capable of raising interrupts (disabled or
 	 * masked), then there's no more work for us to do.
@@ -373,12 +363,19 @@ void kvm_timer_schedule(struct kvm_vcpu *vcpu)
 		return;
 
 	/*
-	 * The guest timers have not yet expired, schedule a background timer.
+	 * At least one guest time will expire. Schedule a background timer.
 	 * Set the earliest expiration time among the guest timers.
 	 */
 	soft_timer_start(&timer->bg_timer, kvm_timer_earliest_exp(vcpu));
 }
 
+static void kvm_timer_unblocking(struct kvm_vcpu *vcpu)
+{
+	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+
+	soft_timer_cancel(&timer->bg_timer);
+}
+
 static void vtimer_restore_state(struct kvm_vcpu *vcpu)
 {
 	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
@@ -401,15 +398,6 @@ static void vtimer_restore_state(struct kvm_vcpu *vcpu)
 	local_irq_restore(flags);
 }
 
-void kvm_timer_unschedule(struct kvm_vcpu *vcpu)
-{
-	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
-
-	vtimer_restore_state(vcpu);
-
-	soft_timer_cancel(&timer->bg_timer);
-}
-
 static void set_cntvoff(u64 cntvoff)
 {
 	u32 low = lower_32_bits(cntvoff);
@@ -485,6 +473,8 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
 	/* Set the background timer for the physical timer emulation. */
 	phys_timer_emulate(vcpu);
 
+	kvm_timer_unblocking(vcpu);
+
 	/* If the timer fired while we weren't running, inject it now */
 	if (kvm_timer_should_fire(ptimer) != ptimer->irq.level)
 		kvm_timer_update_irq(vcpu, !ptimer->irq.level, ptimer);
@@ -527,6 +517,9 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
 	 */
 	soft_timer_cancel(&timer->phys_timer);
 
+	if (swait_active(kvm_arch_vcpu_wq(vcpu)))
+		kvm_timer_blocking(vcpu);
+
 	/*
 	 * The kernel may decide to run userspace after calling vcpu_put, so
 	 * we reset cntvoff to 0 to ensure a consistent read between user
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index b77db673bb03..9fbdb9e1c51f 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -335,13 +335,11 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
 
 void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)
 {
-	kvm_timer_schedule(vcpu);
 	kvm_vgic_v4_enable_doorbell(vcpu);
 }
 
 void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu)
 {
-	kvm_timer_unschedule(vcpu);
 	kvm_vgic_v4_disable_doorbell(vcpu);
 }
 
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 08/14] KVM: arm64: Fix ICH_ELRSR_EL2 sysreg naming
  2019-01-24 14:00 [PATCH 00/14] KVM: arm/arm64: Various rework in preparation of nested virt support Christoffer Dall
                   ` (6 preceding siblings ...)
  2019-01-24 14:00 ` [PATCH 07/14] KVM: arm/arm64: Simplify bg_timer programming Christoffer Dall
@ 2019-01-24 14:00 ` Christoffer Dall
  2019-01-24 14:00 ` [PATCH 09/14] KVM: arm64: Reuse sys_reg() macro when searching the trap table Christoffer Dall
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 33+ messages in thread
From: Christoffer Dall @ 2019-01-24 14:00 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, Christoffer Dall, kvm

From: Marc Zyngier <marc.zyngier@arm.com>

We previously incorrectly named the define for this system register.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
---
 arch/arm/include/asm/arch_gicv3.h | 4 ++--
 arch/arm64/include/asm/sysreg.h   | 2 +-
 virt/kvm/arm/hyp/vgic-v3-sr.c     | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm/include/asm/arch_gicv3.h b/arch/arm/include/asm/arch_gicv3.h
index 0bd530702118..bdc87700def2 100644
--- a/arch/arm/include/asm/arch_gicv3.h
+++ b/arch/arm/include/asm/arch_gicv3.h
@@ -54,7 +54,7 @@
 #define ICH_VTR				__ACCESS_CP15(c12, 4, c11, 1)
 #define ICH_MISR			__ACCESS_CP15(c12, 4, c11, 2)
 #define ICH_EISR			__ACCESS_CP15(c12, 4, c11, 3)
-#define ICH_ELSR			__ACCESS_CP15(c12, 4, c11, 5)
+#define ICH_ELRSR			__ACCESS_CP15(c12, 4, c11, 5)
 #define ICH_VMCR			__ACCESS_CP15(c12, 4, c11, 7)
 
 #define __LR0(x)			__ACCESS_CP15(c12, 4, c12, x)
@@ -151,7 +151,7 @@ CPUIF_MAP(ICH_HCR, ICH_HCR_EL2)
 CPUIF_MAP(ICH_VTR, ICH_VTR_EL2)
 CPUIF_MAP(ICH_MISR, ICH_MISR_EL2)
 CPUIF_MAP(ICH_EISR, ICH_EISR_EL2)
-CPUIF_MAP(ICH_ELSR, ICH_ELSR_EL2)
+CPUIF_MAP(ICH_ELRSR, ICH_ELRSR_EL2)
 CPUIF_MAP(ICH_VMCR, ICH_VMCR_EL2)
 CPUIF_MAP(ICH_AP0R3, ICH_AP0R3_EL2)
 CPUIF_MAP(ICH_AP0R2, ICH_AP0R2_EL2)
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 72dc4c011014..3e5650903d6d 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -426,7 +426,7 @@
 #define SYS_ICH_VTR_EL2			sys_reg(3, 4, 12, 11, 1)
 #define SYS_ICH_MISR_EL2		sys_reg(3, 4, 12, 11, 2)
 #define SYS_ICH_EISR_EL2		sys_reg(3, 4, 12, 11, 3)
-#define SYS_ICH_ELSR_EL2		sys_reg(3, 4, 12, 11, 5)
+#define SYS_ICH_ELRSR_EL2		sys_reg(3, 4, 12, 11, 5)
 #define SYS_ICH_VMCR_EL2		sys_reg(3, 4, 12, 11, 7)
 
 #define __SYS__LR0_EL2(x)		sys_reg(3, 4, 12, 12, x)
diff --git a/virt/kvm/arm/hyp/vgic-v3-sr.c b/virt/kvm/arm/hyp/vgic-v3-sr.c
index 9652c453480f..264d92da3240 100644
--- a/virt/kvm/arm/hyp/vgic-v3-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v3-sr.c
@@ -226,7 +226,7 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
 		int i;
 		u32 elrsr;
 
-		elrsr = read_gicreg(ICH_ELSR_EL2);
+		elrsr = read_gicreg(ICH_ELRSR_EL2);
 
 		write_gicreg(cpu_if->vgic_hcr & ~ICH_HCR_EN, ICH_HCR_EL2);
 
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 09/14] KVM: arm64: Reuse sys_reg() macro when searching the trap table
  2019-01-24 14:00 [PATCH 00/14] KVM: arm/arm64: Various rework in preparation of nested virt support Christoffer Dall
                   ` (7 preceding siblings ...)
  2019-01-24 14:00 ` [PATCH 08/14] KVM: arm64: Fix ICH_ELRSR_EL2 sysreg naming Christoffer Dall
@ 2019-01-24 14:00 ` Christoffer Dall
  2019-01-30  8:57   ` André Przywara
  2019-01-24 14:00 ` [PATCH 10/14] KVM: arm/arm64: consolidate arch timer trap handlers Christoffer Dall
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 33+ messages in thread
From: Christoffer Dall @ 2019-01-24 14:00 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, kvm

From: Marc Zyngier <marc.zyngier@arm.com>

Instead of having an open-coded macro, reuse the sys_reg() macro
that does the exact same thing.

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Christoffer Dall <christoffer.dall@arm.com>
---
 arch/arm64/kvm/sys_regs.c | 19 ++++++-------------
 1 file changed, 6 insertions(+), 13 deletions(-)

diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index e3e37228ae4e..1a5bea4285e4 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -965,6 +965,10 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	return true;
 }
 
+#define reg_to_encoding(x)						\
+	sys_reg((u32)(x)->Op0, (u32)(x)->Op1,				\
+		(u32)(x)->CRn, (u32)(x)->CRm, (u32)(x)->Op2);
+
 /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */
 #define DBG_BCR_BVR_WCR_WVR_EL1(n)					\
 	{ SYS_DESC(SYS_DBGBVRn_EL1(n)),					\
@@ -1820,30 +1824,19 @@ static const struct sys_reg_desc *get_target_table(unsigned target,
 	}
 }
 
-#define reg_to_match_value(x)						\
-	({								\
-		unsigned long val;					\
-		val  = (x)->Op0 << 14;					\
-		val |= (x)->Op1 << 11;					\
-		val |= (x)->CRn << 7;					\
-		val |= (x)->CRm << 3;					\
-		val |= (x)->Op2;					\
-		val;							\
-	 })
-
 static int match_sys_reg(const void *key, const void *elt)
 {
 	const unsigned long pval = (unsigned long)key;
 	const struct sys_reg_desc *r = elt;
 
-	return pval - reg_to_match_value(r);
+	return pval - reg_to_encoding(r);
 }
 
 static const struct sys_reg_desc *find_reg(const struct sys_reg_params *params,
 					 const struct sys_reg_desc table[],
 					 unsigned int num)
 {
-	unsigned long pval = reg_to_match_value(params);
+	unsigned long pval = reg_to_encoding(params);
 
 	return bsearch((void *)pval, table, num, sizeof(table[0]), match_sys_reg);
 }
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 10/14] KVM: arm/arm64: consolidate arch timer trap handlers
  2019-01-24 14:00 [PATCH 00/14] KVM: arm/arm64: Various rework in preparation of nested virt support Christoffer Dall
                   ` (8 preceding siblings ...)
  2019-01-24 14:00 ` [PATCH 09/14] KVM: arm64: Reuse sys_reg() macro when searching the trap table Christoffer Dall
@ 2019-01-24 14:00 ` Christoffer Dall
  2019-01-25 12:33   ` Julien Thierry
  2019-01-24 14:00 ` [PATCH 11/14] KVM: arm/arm64: timer: Rework data structures for multiple timers Christoffer Dall
                   ` (3 subsequent siblings)
  13 siblings, 1 reply; 33+ messages in thread
From: Christoffer Dall @ 2019-01-24 14:00 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Marc Zyngier, Andre Przywara, Christoffer Dall, kvm

From: Andre Przywara <andre.przywara@arm.com>

At the moment we have separate system register emulation handlers for
each timer register. Actually they are quite similar, and we rely on
kvm_arm_timer_[gs]et_reg() for the actual emulation anyways, so let's
just merge all of those handlers into one function, which just marshalls
the arguments and then hands off to a set of common accessors.
This makes extending the emulation to include EL2 timers much easier.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
[Fixed 32-bit VM breakage and reduced to reworking existing code]
Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
[Fixed 32bit host, general cleanup]
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/kvm/coproc.c           |  23 +++---
 arch/arm64/include/asm/sysreg.h |   4 +
 arch/arm64/kvm/sys_regs.c       |  80 +++++++++++---------
 include/kvm/arm_arch_timer.h    |  23 ++++++
 virt/kvm/arm/arch_timer.c       | 129 +++++++++++++++++++++++++++-----
 5 files changed, 196 insertions(+), 63 deletions(-)

diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
index 222c1635bc7a..51863364f8d1 100644
--- a/arch/arm/kvm/coproc.c
+++ b/arch/arm/kvm/coproc.c
@@ -293,15 +293,16 @@ static bool access_cntp_tval(struct kvm_vcpu *vcpu,
 			     const struct coproc_params *p,
 			     const struct coproc_reg *r)
 {
-	u64 now = kvm_phys_timer_read();
-	u64 val;
+	u32 val;
 
 	if (p->is_write) {
 		val = *vcpu_reg(vcpu, p->Rt1);
-		kvm_arm_timer_set_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL, val + now);
+		kvm_arm_timer_write_sysreg(vcpu,
+					   TIMER_PTIMER, TIMER_REG_TVAL, val);
 	} else {
-		val = kvm_arm_timer_get_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL);
-		*vcpu_reg(vcpu, p->Rt1) = val - now;
+		val = kvm_arm_timer_read_sysreg(vcpu,
+						TIMER_PTIMER, TIMER_REG_TVAL);
+		*vcpu_reg(vcpu, p->Rt1) = val;
 	}
 
 	return true;
@@ -315,9 +316,11 @@ static bool access_cntp_ctl(struct kvm_vcpu *vcpu,
 
 	if (p->is_write) {
 		val = *vcpu_reg(vcpu, p->Rt1);
-		kvm_arm_timer_set_reg(vcpu, KVM_REG_ARM_PTIMER_CTL, val);
+		kvm_arm_timer_write_sysreg(vcpu,
+					   TIMER_PTIMER, TIMER_REG_CTL, val);
 	} else {
-		val = kvm_arm_timer_get_reg(vcpu, KVM_REG_ARM_PTIMER_CTL);
+		val = kvm_arm_timer_read_sysreg(vcpu,
+						TIMER_PTIMER, TIMER_REG_CTL);
 		*vcpu_reg(vcpu, p->Rt1) = val;
 	}
 
@@ -333,9 +336,11 @@ static bool access_cntp_cval(struct kvm_vcpu *vcpu,
 	if (p->is_write) {
 		val = (u64)*vcpu_reg(vcpu, p->Rt2) << 32;
 		val |= *vcpu_reg(vcpu, p->Rt1);
-		kvm_arm_timer_set_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL, val);
+		kvm_arm_timer_write_sysreg(vcpu,
+					   TIMER_PTIMER, TIMER_REG_CVAL, val);
 	} else {
-		val = kvm_arm_timer_get_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL);
+		val = kvm_arm_timer_read_sysreg(vcpu,
+						TIMER_PTIMER, TIMER_REG_CVAL);
 		*vcpu_reg(vcpu, p->Rt1) = val;
 		*vcpu_reg(vcpu, p->Rt2) = val >> 32;
 	}
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 3e5650903d6d..6482e8bcf1b8 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -392,6 +392,10 @@
 #define SYS_CNTP_CTL_EL0		sys_reg(3, 3, 14, 2, 1)
 #define SYS_CNTP_CVAL_EL0		sys_reg(3, 3, 14, 2, 2)
 
+#define SYS_AARCH32_CNTP_TVAL		sys_reg(0, 0, 14, 2, 0)
+#define SYS_AARCH32_CNTP_CTL		sys_reg(0, 0, 14, 2, 1)
+#define SYS_AARCH32_CNTP_CVAL		sys_reg(0, 2, 0, 14, 0)
+
 #define __PMEV_op2(n)			((n) & 0x7)
 #define __CNTR_CRm(n)			(0x8 | (((n) >> 3) & 0x3))
 #define SYS_PMEVCNTRn_EL0(n)		sys_reg(3, 3, 14, __CNTR_CRm(n), __PMEV_op2(n))
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 1a5bea4285e4..65ea63366c67 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -990,44 +990,51 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
 	{ SYS_DESC(SYS_PMEVTYPERn_EL0(n)),					\
 	  access_pmu_evtyper, reset_unknown, (PMEVTYPER0_EL0 + n), }
 
-static bool access_cntp_tval(struct kvm_vcpu *vcpu,
-		struct sys_reg_params *p,
-		const struct sys_reg_desc *r)
+static bool access_arch_timer(struct kvm_vcpu *vcpu,
+			      struct sys_reg_params *p,
+			      const struct sys_reg_desc *r)
 {
-	u64 now = kvm_phys_timer_read();
-	u64 cval;
+	enum kvm_arch_timers tmr;
+	enum kvm_arch_timer_regs treg;
+	u64 reg = reg_to_encoding(r);
 
-	if (p->is_write) {
-		kvm_arm_timer_set_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL,
-				      p->regval + now);
-	} else {
-		cval = kvm_arm_timer_get_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL);
-		p->regval = cval - now;
+	switch (reg) {
+	case SYS_CNTP_TVAL_EL0:
+	case SYS_CNTP_CTL_EL0:
+	case SYS_CNTP_CVAL_EL0:
+	case SYS_AARCH32_CNTP_TVAL:
+	case SYS_AARCH32_CNTP_CTL:
+	case SYS_AARCH32_CNTP_CVAL:
+		tmr = TIMER_PTIMER;
+		break;
+	default:
+		BUG();
 	}
 
-	return true;
-}
+	switch (reg) {
+	case SYS_CNTP_CVAL_EL0:
+	case SYS_AARCH32_CNTP_CVAL:
+		treg = TIMER_REG_CVAL;
+		break;
 
-static bool access_cntp_ctl(struct kvm_vcpu *vcpu,
-		struct sys_reg_params *p,
-		const struct sys_reg_desc *r)
-{
-	if (p->is_write)
-		kvm_arm_timer_set_reg(vcpu, KVM_REG_ARM_PTIMER_CTL, p->regval);
-	else
-		p->regval = kvm_arm_timer_get_reg(vcpu, KVM_REG_ARM_PTIMER_CTL);
+	case SYS_CNTP_TVAL_EL0:
+	case SYS_AARCH32_CNTP_TVAL:
+		treg = TIMER_REG_TVAL;
+		break;
 
-	return true;
-}
+	case SYS_CNTP_CTL_EL0:
+	case SYS_AARCH32_CNTP_CTL:
+		treg = TIMER_REG_CTL;
+		break;
+
+	default:
+		BUG();
+	}
 
-static bool access_cntp_cval(struct kvm_vcpu *vcpu,
-		struct sys_reg_params *p,
-		const struct sys_reg_desc *r)
-{
 	if (p->is_write)
-		kvm_arm_timer_set_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL, p->regval);
+		kvm_arm_timer_write_sysreg(vcpu, tmr, treg, p->regval);
 	else
-		p->regval = kvm_arm_timer_get_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL);
+		p->regval = kvm_arm_timer_read_sysreg(vcpu, tmr, treg);
 
 	return true;
 }
@@ -1392,9 +1399,9 @@ static const struct sys_reg_desc sys_reg_descs[] = {
 	{ SYS_DESC(SYS_TPIDR_EL0), NULL, reset_unknown, TPIDR_EL0 },
 	{ SYS_DESC(SYS_TPIDRRO_EL0), NULL, reset_unknown, TPIDRRO_EL0 },
 
-	{ SYS_DESC(SYS_CNTP_TVAL_EL0), access_cntp_tval },
-	{ SYS_DESC(SYS_CNTP_CTL_EL0), access_cntp_ctl },
-	{ SYS_DESC(SYS_CNTP_CVAL_EL0), access_cntp_cval },
+	{ SYS_DESC(SYS_CNTP_TVAL_EL0), access_arch_timer },
+	{ SYS_DESC(SYS_CNTP_CTL_EL0), access_arch_timer },
+	{ SYS_DESC(SYS_CNTP_CVAL_EL0), access_arch_timer },
 
 	/* PMEVCNTRn_EL0 */
 	PMU_PMEVCNTR_EL0(0),
@@ -1715,10 +1722,9 @@ static const struct sys_reg_desc cp15_regs[] = {
 
 	{ Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, c13_CID },
 
-	/* CNTP_TVAL */
-	{ Op1( 0), CRn(14), CRm( 2), Op2( 0), access_cntp_tval },
-	/* CNTP_CTL */
-	{ Op1( 0), CRn(14), CRm( 2), Op2( 1), access_cntp_ctl },
+	/* Arch Tmers */
+	{ SYS_DESC(SYS_AARCH32_CNTP_TVAL), access_arch_timer },
+	{ SYS_DESC(SYS_AARCH32_CNTP_CTL), access_arch_timer },
 
 	/* PMEVCNTRn */
 	PMU_PMEVCNTR(0),
@@ -1795,7 +1801,7 @@ static const struct sys_reg_desc cp15_64_regs[] = {
 	{ Op1( 1), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR1 },
 	{ Op1( 1), CRn( 0), CRm(12), Op2( 0), access_gic_sgi }, /* ICC_ASGI1R */
 	{ Op1( 2), CRn( 0), CRm(12), Op2( 0), access_gic_sgi }, /* ICC_SGI0R */
-	{ Op1( 2), CRn( 0), CRm(14), Op2( 0), access_cntp_cval },
+	{ SYS_DESC(SYS_AARCH32_CNTP_CVAL),    access_arch_timer },
 };
 
 /* Target specific emulation tables */
diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index d6e6a45d1d24..d26b7fde9935 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -22,6 +22,19 @@
 #include <linux/clocksource.h>
 #include <linux/hrtimer.h>
 
+enum kvm_arch_timers {
+	TIMER_PTIMER,
+	TIMER_VTIMER,
+	NR_KVM_TIMERS
+};
+
+enum kvm_arch_timer_regs {
+	TIMER_REG_CNT,
+	TIMER_REG_CVAL,
+	TIMER_REG_TVAL,
+	TIMER_REG_CTL,
+};
+
 struct arch_timer_context {
 	/* Registers: control register, timer value */
 	u32				cnt_ctl;
@@ -87,5 +100,15 @@ bool kvm_arch_timer_get_input_level(int vintid);
 
 #define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.vtimer)
 #define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.ptimer)
+#define vcpu_get_timer(v,t)					\
+	(t == TIMER_VTIMER ? vcpu_vtimer(v) : vcpu_ptimer(v))
+
+u64 kvm_arm_timer_read_sysreg(struct kvm_vcpu *vcpu,
+			      enum kvm_arch_timers tmr,
+			      enum kvm_arch_timer_regs treg);
+void kvm_arm_timer_write_sysreg(struct kvm_vcpu *vcpu,
+				enum kvm_arch_timers tmr,
+				enum kvm_arch_timer_regs treg,
+				u64 val);
 
 #endif
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 4986028d9829..9502bb91776b 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -25,6 +25,7 @@
 
 #include <clocksource/arm_arch_timer.h>
 #include <asm/arch_timer.h>
+#include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
 
 #include <kvm/arm_vgic.h>
@@ -52,6 +53,13 @@ static bool kvm_timer_irq_can_fire(struct arch_timer_context *timer_ctx);
 static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
 				 struct arch_timer_context *timer_ctx);
 static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx);
+static void kvm_arm_timer_write(struct kvm_vcpu *vcpu,
+				struct arch_timer_context *timer,
+				enum kvm_arch_timer_regs treg,
+				u64 val);
+static u64 kvm_arm_timer_read(struct kvm_vcpu *vcpu,
+			      struct arch_timer_context *timer,
+			      enum kvm_arch_timer_regs treg);
 
 u64 kvm_phys_timer_read(void)
 {
@@ -628,24 +636,25 @@ static void kvm_timer_init_interrupt(void *info)
 
 int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
 {
-	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
-	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
-
 	switch (regid) {
 	case KVM_REG_ARM_TIMER_CTL:
-		vtimer->cnt_ctl = value & ~ARCH_TIMER_CTRL_IT_STAT;
+		kvm_arm_timer_write(vcpu,
+				    vcpu_vtimer(vcpu), TIMER_REG_CTL, value);
 		break;
 	case KVM_REG_ARM_TIMER_CNT:
 		update_vtimer_cntvoff(vcpu, kvm_phys_timer_read() - value);
 		break;
 	case KVM_REG_ARM_TIMER_CVAL:
-		vtimer->cnt_cval = value;
+		kvm_arm_timer_write(vcpu,
+				    vcpu_vtimer(vcpu), TIMER_REG_CVAL, value);
 		break;
 	case KVM_REG_ARM_PTIMER_CTL:
-		ptimer->cnt_ctl = value & ~ARCH_TIMER_CTRL_IT_STAT;
+		kvm_arm_timer_write(vcpu,
+				    vcpu_ptimer(vcpu), TIMER_REG_CTL, value);
 		break;
 	case KVM_REG_ARM_PTIMER_CVAL:
-		ptimer->cnt_cval = value;
+		kvm_arm_timer_write(vcpu,
+				    vcpu_ptimer(vcpu), TIMER_REG_CVAL, value);
 		break;
 
 	default:
@@ -672,26 +681,112 @@ static u64 read_timer_ctl(struct arch_timer_context *timer)
 
 u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid)
 {
-	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
-	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
-
 	switch (regid) {
 	case KVM_REG_ARM_TIMER_CTL:
-		return read_timer_ctl(vtimer);
+		return kvm_arm_timer_read(vcpu,
+					  vcpu_vtimer(vcpu), TIMER_REG_CTL);
 	case KVM_REG_ARM_TIMER_CNT:
-		return kvm_phys_timer_read() - vtimer->cntvoff;
+		return kvm_arm_timer_read(vcpu,
+					  vcpu_vtimer(vcpu), TIMER_REG_CNT);
 	case KVM_REG_ARM_TIMER_CVAL:
-		return vtimer->cnt_cval;
+		return kvm_arm_timer_read(vcpu,
+					  vcpu_vtimer(vcpu), TIMER_REG_CVAL);
 	case KVM_REG_ARM_PTIMER_CTL:
-		return read_timer_ctl(ptimer);
-	case KVM_REG_ARM_PTIMER_CVAL:
-		return ptimer->cnt_cval;
+		return kvm_arm_timer_read(vcpu,
+					  vcpu_ptimer(vcpu), TIMER_REG_CTL);
 	case KVM_REG_ARM_PTIMER_CNT:
-		return kvm_phys_timer_read();
+		return kvm_arm_timer_read(vcpu,
+					  vcpu_vtimer(vcpu), TIMER_REG_CNT);
+	case KVM_REG_ARM_PTIMER_CVAL:
+		return kvm_arm_timer_read(vcpu,
+					  vcpu_ptimer(vcpu), TIMER_REG_CVAL);
 	}
 	return (u64)-1;
 }
 
+static u64 kvm_arm_timer_read(struct kvm_vcpu *vcpu,
+			      struct arch_timer_context *timer,
+			      enum kvm_arch_timer_regs treg)
+{
+	u64 val;
+
+	switch (treg) {
+	case TIMER_REG_TVAL:
+		val = kvm_phys_timer_read() - timer->cntvoff - timer->cnt_cval;
+		break;
+
+	case TIMER_REG_CTL:
+		val = read_timer_ctl(timer);
+		break;
+
+	case TIMER_REG_CVAL:
+		val = timer->cnt_cval;
+		break;
+
+	case TIMER_REG_CNT:
+		val = kvm_phys_timer_read() - timer->cntvoff;
+
+	default:
+		BUG();
+	}
+
+	return val;
+}
+
+u64 kvm_arm_timer_read_sysreg(struct kvm_vcpu *vcpu,
+			      enum kvm_arch_timers tmr,
+			      enum kvm_arch_timer_regs treg)
+{
+	u64 val;
+
+	preempt_disable();
+	kvm_timer_vcpu_put(vcpu);
+
+	val = kvm_arm_timer_read(vcpu, vcpu_get_timer(vcpu, tmr), treg);
+
+	kvm_timer_vcpu_load(vcpu);
+	preempt_enable();
+
+	return val;
+}
+
+static void kvm_arm_timer_write(struct kvm_vcpu *vcpu,
+				struct arch_timer_context *timer,
+				enum kvm_arch_timer_regs treg,
+				u64 val)
+{
+	switch (treg) {
+	case TIMER_REG_TVAL:
+		timer->cnt_cval = val - kvm_phys_timer_read() - timer->cntvoff;
+		break;
+
+	case TIMER_REG_CTL:
+		timer->cnt_ctl = val & ~ARCH_TIMER_CTRL_IT_STAT;
+		break;
+
+	case TIMER_REG_CVAL:
+		timer->cnt_cval = val;
+		break;
+
+	default:
+		BUG();
+	}
+}
+
+void kvm_arm_timer_write_sysreg(struct kvm_vcpu *vcpu,
+				enum kvm_arch_timers tmr,
+				enum kvm_arch_timer_regs treg,
+				u64 val)
+{
+	preempt_disable();
+	kvm_timer_vcpu_put(vcpu);
+
+	kvm_arm_timer_write(vcpu, vcpu_get_timer(vcpu, tmr), treg, val);
+
+	kvm_timer_vcpu_load(vcpu);
+	preempt_enable();
+}
+
 static int kvm_timer_starting_cpu(unsigned int cpu)
 {
 	kvm_timer_init_interrupt(NULL);
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 11/14] KVM: arm/arm64: timer: Rework data structures for multiple timers
  2019-01-24 14:00 [PATCH 00/14] KVM: arm/arm64: Various rework in preparation of nested virt support Christoffer Dall
                   ` (9 preceding siblings ...)
  2019-01-24 14:00 ` [PATCH 10/14] KVM: arm/arm64: consolidate arch timer trap handlers Christoffer Dall
@ 2019-01-24 14:00 ` Christoffer Dall
  2019-02-18 15:10   ` André Przywara
  2019-01-24 14:00 ` [PATCH 12/14] KVM: arm/arm64: arch_timer: Assign the phys timer on VHE systems Christoffer Dall
                   ` (2 subsequent siblings)
  13 siblings, 1 reply; 33+ messages in thread
From: Christoffer Dall @ 2019-01-24 14:00 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, Christoffer Dall, kvm

Prepare for having 4 timer data structures (2 for now).

Change loaded to an enum so that we know not just whether *some* state
is loaded on the CPU, but also *which* state is loaded.

Move loaded to the cpu data structure and not the individual timer
structure, in preparation for assigning the EL1 phys timer as well.

Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
---
 include/kvm/arm_arch_timer.h | 44 ++++++++++++++-------------
 virt/kvm/arm/arch_timer.c    | 58 +++++++++++++++++++-----------------
 2 files changed, 54 insertions(+), 48 deletions(-)

diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index d26b7fde9935..d40fe57a2d0d 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -36,6 +36,8 @@ enum kvm_arch_timer_regs {
 };
 
 struct arch_timer_context {
+	struct kvm_vcpu			*vcpu;
+
 	/* Registers: control register, timer value */
 	u32				cnt_ctl;
 	u64				cnt_cval;
@@ -43,32 +45,34 @@ struct arch_timer_context {
 	/* Timer IRQ */
 	struct kvm_irq_level		irq;
 
-	/*
-	 * We have multiple paths which can save/restore the timer state
-	 * onto the hardware, so we need some way of keeping track of
-	 * where the latest state is.
-	 *
-	 * loaded == true:  State is loaded on the hardware registers.
-	 * loaded == false: State is stored in memory.
-	 */
-	bool			loaded;
-
 	/* Virtual offset */
-	u64			cntvoff;
+	u64				cntvoff;
+
+	/* Emulated Timer (may be unused) */
+	struct hrtimer			hrtimer;
+};
+
+enum loaded_timer_state {
+	TIMER_NOT_LOADED,
+	TIMER_EL1_LOADED,
 };
 
 struct arch_timer_cpu {
-	struct arch_timer_context	vtimer;
-	struct arch_timer_context	ptimer;
+	struct arch_timer_context timers[NR_KVM_TIMERS];
 
 	/* Background timer used when the guest is not running */
 	struct hrtimer			bg_timer;
 
-	/* Physical timer emulation */
-	struct hrtimer			phys_timer;
-
 	/* Is the timer enabled */
 	bool			enabled;
+
+	/*
+	 * We have multiple paths which can save/restore the timer state
+	 * onto the hardware, and for nested virt the EL1 hardware timers can
+	 * contain state from either the VM's EL1 timers or EL2 timers, so we
+	 * need some way of keeping track of where the latest state is.
+	 */
+	enum loaded_timer_state loaded;
 };
 
 int kvm_timer_hyp_init(bool);
@@ -98,10 +102,10 @@ void kvm_timer_init_vhe(void);
 
 bool kvm_arch_timer_get_input_level(int vintid);
 
-#define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.vtimer)
-#define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.ptimer)
-#define vcpu_get_timer(v,t)					\
-	(t == TIMER_VTIMER ? vcpu_vtimer(v) : vcpu_ptimer(v))
+#define vcpu_timer(v)	(&(v)->arch.timer_cpu)
+#define vcpu_get_timer(v,t)	(&vcpu_timer(v)->timers[(t)])
+#define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.timers[TIMER_VTIMER])
+#define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.timers[TIMER_PTIMER])
 
 u64 kvm_arm_timer_read_sysreg(struct kvm_vcpu *vcpu,
 			      enum kvm_arch_timers tmr,
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 9502bb91776b..8b0eca5fbad1 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -184,13 +184,11 @@ static enum hrtimer_restart kvm_bg_timer_expire(struct hrtimer *hrt)
 static enum hrtimer_restart kvm_phys_timer_expire(struct hrtimer *hrt)
 {
 	struct arch_timer_context *ptimer;
-	struct arch_timer_cpu *timer;
 	struct kvm_vcpu *vcpu;
 	u64 ns;
 
-	timer = container_of(hrt, struct arch_timer_cpu, phys_timer);
-	vcpu = container_of(timer, struct kvm_vcpu, arch.timer_cpu);
-	ptimer = vcpu_ptimer(vcpu);
+	ptimer = container_of(hrt, struct arch_timer_context, hrtimer);
+	vcpu = ptimer->vcpu;
 
 	/*
 	 * Check that the timer has really expired from the guest's
@@ -209,9 +207,10 @@ static enum hrtimer_restart kvm_phys_timer_expire(struct hrtimer *hrt)
 
 static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx)
 {
+	struct arch_timer_cpu *timer = vcpu_timer(timer_ctx->vcpu);
 	u64 cval, now;
 
-	if (timer_ctx->loaded) {
+	if (timer->loaded == TIMER_EL1_LOADED) {
 		u32 cnt_ctl;
 
 		/* Only the virtual timer can be loaded so far */
@@ -280,7 +279,6 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
 /* Schedule the background timer for the emulated timer. */
 static void phys_timer_emulate(struct kvm_vcpu *vcpu)
 {
-	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
 	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
 
 	/*
@@ -289,11 +287,11 @@ static void phys_timer_emulate(struct kvm_vcpu *vcpu)
 	 * then we also don't need a soft timer.
 	 */
 	if (kvm_timer_should_fire(ptimer) || !kvm_timer_irq_can_fire(ptimer)) {
-		soft_timer_cancel(&timer->phys_timer);
+		soft_timer_cancel(&ptimer->hrtimer);
 		return;
 	}
 
-	soft_timer_start(&timer->phys_timer, kvm_timer_compute_delta(ptimer));
+	soft_timer_start(&ptimer->hrtimer, kvm_timer_compute_delta(ptimer));
 }
 
 /*
@@ -303,7 +301,7 @@ static void phys_timer_emulate(struct kvm_vcpu *vcpu)
  */
 static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
 {
-	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
 	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
 	bool level;
@@ -329,13 +327,13 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
 
 static void vtimer_save_state(struct kvm_vcpu *vcpu)
 {
-	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
 	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 	unsigned long flags;
 
 	local_irq_save(flags);
 
-	if (!vtimer->loaded)
+	if (timer->loaded == TIMER_NOT_LOADED)
 		goto out;
 
 	if (timer->enabled) {
@@ -347,7 +345,7 @@ static void vtimer_save_state(struct kvm_vcpu *vcpu)
 	write_sysreg_el0(0, cntv_ctl);
 	isb();
 
-	vtimer->loaded = false;
+	timer->loaded = TIMER_NOT_LOADED;
 out:
 	local_irq_restore(flags);
 }
@@ -359,7 +357,7 @@ static void vtimer_save_state(struct kvm_vcpu *vcpu)
  */
 static void kvm_timer_blocking(struct kvm_vcpu *vcpu)
 {
-	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
 	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
 
@@ -379,20 +377,20 @@ static void kvm_timer_blocking(struct kvm_vcpu *vcpu)
 
 static void kvm_timer_unblocking(struct kvm_vcpu *vcpu)
 {
-	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
 
 	soft_timer_cancel(&timer->bg_timer);
 }
 
 static void vtimer_restore_state(struct kvm_vcpu *vcpu)
 {
-	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
 	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 	unsigned long flags;
 
 	local_irq_save(flags);
 
-	if (vtimer->loaded)
+	if (timer->loaded == TIMER_EL1_LOADED)
 		goto out;
 
 	if (timer->enabled) {
@@ -401,7 +399,7 @@ static void vtimer_restore_state(struct kvm_vcpu *vcpu)
 		write_sysreg_el0(vtimer->cnt_ctl, cntv_ctl);
 	}
 
-	vtimer->loaded = true;
+	timer->loaded = TIMER_EL1_LOADED;
 out:
 	local_irq_restore(flags);
 }
@@ -462,7 +460,7 @@ static void kvm_timer_vcpu_load_nogic(struct kvm_vcpu *vcpu)
 
 void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
 {
-	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
 	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
 
@@ -507,7 +505,8 @@ bool kvm_timer_should_notify_user(struct kvm_vcpu *vcpu)
 
 void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
 {
-	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
+	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
 
 	if (unlikely(!timer->enabled))
 		return;
@@ -523,7 +522,7 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
 	 * In any case, we re-schedule the hrtimer for the physical timer when
 	 * coming back to the VCPU thread in kvm_timer_vcpu_load().
 	 */
-	soft_timer_cancel(&timer->phys_timer);
+	soft_timer_cancel(&ptimer->hrtimer);
 
 	if (swait_active(kvm_arch_vcpu_wq(vcpu)))
 		kvm_timer_blocking(vcpu);
@@ -559,7 +558,7 @@ static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu)
 
 void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
 {
-	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
 
 	if (unlikely(!timer->enabled))
 		return;
@@ -570,7 +569,7 @@ void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
 
 int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu)
 {
-	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
 	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
 
@@ -611,22 +610,25 @@ static void update_vtimer_cntvoff(struct kvm_vcpu *vcpu, u64 cntvoff)
 
 void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
 {
-	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
 	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
 
 	/* Synchronize cntvoff across all vtimers of a VM. */
 	update_vtimer_cntvoff(vcpu, kvm_phys_timer_read());
-	vcpu_ptimer(vcpu)->cntvoff = 0;
+	ptimer->cntvoff = 0;
 
 	hrtimer_init(&timer->bg_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
 	timer->bg_timer.function = kvm_bg_timer_expire;
 
-	hrtimer_init(&timer->phys_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
-	timer->phys_timer.function = kvm_phys_timer_expire;
+	hrtimer_init(&ptimer->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+	ptimer->hrtimer.function = kvm_phys_timer_expire;
 
 	vtimer->irq.irq = default_vtimer_irq.irq;
 	ptimer->irq.irq = default_ptimer_irq.irq;
+
+	vtimer->vcpu = vcpu;
+	ptimer->vcpu = vcpu;
 }
 
 static void kvm_timer_init_interrupt(void *info)
@@ -859,7 +861,7 @@ int kvm_timer_hyp_init(bool has_gic)
 
 void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu)
 {
-	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
 
 	soft_timer_cancel(&timer->bg_timer);
 }
@@ -903,7 +905,7 @@ bool kvm_arch_timer_get_input_level(int vintid)
 
 int kvm_timer_enable(struct kvm_vcpu *vcpu)
 {
-	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
 	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 	int ret;
 
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 12/14] KVM: arm/arm64: arch_timer: Assign the phys timer on VHE systems
  2019-01-24 14:00 [PATCH 00/14] KVM: arm/arm64: Various rework in preparation of nested virt support Christoffer Dall
                   ` (10 preceding siblings ...)
  2019-01-24 14:00 ` [PATCH 11/14] KVM: arm/arm64: timer: Rework data structures for multiple timers Christoffer Dall
@ 2019-01-24 14:00 ` Christoffer Dall
  2019-02-18 15:10   ` André Przywara
  2019-02-19 11:39   ` Alexandru Elisei
  2019-01-24 14:00 ` [PATCH 13/14] KVM: arm/arm64: Rework the timer code to use a timer_map Christoffer Dall
  2019-01-24 14:00 ` [PATCH 14/14] KVM: arm/arm64: Move kvm_is_write_fault to header file Christoffer Dall
  13 siblings, 2 replies; 33+ messages in thread
From: Christoffer Dall @ 2019-01-24 14:00 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, Christoffer Dall, kvm

VHE systems don't have to emulate the physical timer, we can simply
assigne the EL1 physical timer directly to the VM as the host always
uses the EL2 timers.

In order to minimize the amount of cruft, AArch32 gets definitions for
the physical timer too, but is should be generally unused on this
architecture.

Co-written with Marc Zyngier <marc.zyngier@arm.com>

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
---
 arch/arm/include/asm/kvm_hyp.h |   4 +
 include/kvm/arm_arch_timer.h   |   6 +
 virt/kvm/arm/arch_timer.c      | 206 ++++++++++++++++++++++++++-------
 3 files changed, 171 insertions(+), 45 deletions(-)

diff --git a/arch/arm/include/asm/kvm_hyp.h b/arch/arm/include/asm/kvm_hyp.h
index e93a0cac9add..87bcd18df8d5 100644
--- a/arch/arm/include/asm/kvm_hyp.h
+++ b/arch/arm/include/asm/kvm_hyp.h
@@ -40,6 +40,7 @@
 #define TTBR1		__ACCESS_CP15_64(1, c2)
 #define VTTBR		__ACCESS_CP15_64(6, c2)
 #define PAR		__ACCESS_CP15_64(0, c7)
+#define CNTP_CVAL	__ACCESS_CP15_64(2, c14)
 #define CNTV_CVAL	__ACCESS_CP15_64(3, c14)
 #define CNTVOFF		__ACCESS_CP15_64(4, c14)
 
@@ -85,6 +86,7 @@
 #define TID_PRIV	__ACCESS_CP15(c13, 0, c0, 4)
 #define HTPIDR		__ACCESS_CP15(c13, 4, c0, 2)
 #define CNTKCTL		__ACCESS_CP15(c14, 0, c1, 0)
+#define CNTP_CTL	__ACCESS_CP15(c14, 0, c2, 1)
 #define CNTV_CTL	__ACCESS_CP15(c14, 0, c3, 1)
 #define CNTHCTL		__ACCESS_CP15(c14, 4, c1, 0)
 
@@ -94,6 +96,8 @@
 #define read_sysreg_el0(r)		read_sysreg(r##_el0)
 #define write_sysreg_el0(v, r)		write_sysreg(v, r##_el0)
 
+#define cntp_ctl_el0			CNTP_CTL
+#define cntp_cval_el0			CNTP_CVAL
 #define cntv_ctl_el0			CNTV_CTL
 #define cntv_cval_el0			CNTV_CVAL
 #define cntvoff_el2			CNTVOFF
diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index d40fe57a2d0d..722e0481f310 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -50,6 +50,10 @@ struct arch_timer_context {
 
 	/* Emulated Timer (may be unused) */
 	struct hrtimer			hrtimer;
+
+	/* Duplicated state from arch_timer.c for convenience */
+	u32				host_timer_irq;
+	u32				host_timer_irq_flags;
 };
 
 enum loaded_timer_state {
@@ -107,6 +111,8 @@ bool kvm_arch_timer_get_input_level(int vintid);
 #define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.timers[TIMER_VTIMER])
 #define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.timers[TIMER_PTIMER])
 
+#define arch_timer_ctx_index(ctx)	((ctx) - vcpu_timer((ctx)->vcpu)->timers)
+
 u64 kvm_arm_timer_read_sysreg(struct kvm_vcpu *vcpu,
 			      enum kvm_arch_timers tmr,
 			      enum kvm_arch_timer_regs treg);
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 8b0eca5fbad1..eed8f48fbf9b 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -35,7 +35,9 @@
 
 static struct timecounter *timecounter;
 static unsigned int host_vtimer_irq;
+static unsigned int host_ptimer_irq;
 static u32 host_vtimer_irq_flags;
+static u32 host_ptimer_irq_flags;
 
 static DEFINE_STATIC_KEY_FALSE(has_gic_active_state);
 
@@ -86,20 +88,24 @@ static void soft_timer_cancel(struct hrtimer *hrt)
 static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
 {
 	struct kvm_vcpu *vcpu = *(struct kvm_vcpu **)dev_id;
-	struct arch_timer_context *vtimer;
+	struct arch_timer_context *ctx;
 
 	/*
 	 * We may see a timer interrupt after vcpu_put() has been called which
 	 * sets the CPU's vcpu pointer to NULL, because even though the timer
-	 * has been disabled in vtimer_save_state(), the hardware interrupt
+	 * has been disabled in timer_save_state(), the hardware interrupt
 	 * signal may not have been retired from the interrupt controller yet.
 	 */
 	if (!vcpu)
 		return IRQ_HANDLED;
 
-	vtimer = vcpu_vtimer(vcpu);
-	if (kvm_timer_should_fire(vtimer))
-		kvm_timer_update_irq(vcpu, true, vtimer);
+	if (irq == host_vtimer_irq)
+		ctx = vcpu_vtimer(vcpu);
+	else
+		ctx = vcpu_ptimer(vcpu);
+
+	if (kvm_timer_should_fire(ctx))
+		kvm_timer_update_irq(vcpu, true, ctx);
 
 	if (userspace_irqchip(vcpu->kvm) &&
 	    !static_branch_unlikely(&has_gic_active_state))
@@ -208,13 +214,25 @@ static enum hrtimer_restart kvm_phys_timer_expire(struct hrtimer *hrt)
 static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx)
 {
 	struct arch_timer_cpu *timer = vcpu_timer(timer_ctx->vcpu);
+	enum kvm_arch_timers index = arch_timer_ctx_index(timer_ctx);
 	u64 cval, now;
 
 	if (timer->loaded == TIMER_EL1_LOADED) {
-		u32 cnt_ctl;
+		u32 cnt_ctl = 0;
+
+		switch (index) {
+		case TIMER_VTIMER:
+			cnt_ctl = read_sysreg_el0(cntv_ctl);
+			break;
+		case TIMER_PTIMER:
+			cnt_ctl = read_sysreg_el0(cntp_ctl);
+			break;
+		case NR_KVM_TIMERS:
+			/* GCC is braindead */
+			cnt_ctl = 0;
+			break;
+		}
 
-		/* Only the virtual timer can be loaded so far */
-		cnt_ctl = read_sysreg_el0(cntv_ctl);
 		return  (cnt_ctl & ARCH_TIMER_CTRL_ENABLE) &&
 		        (cnt_ctl & ARCH_TIMER_CTRL_IT_STAT) &&
 		       !(cnt_ctl & ARCH_TIMER_CTRL_IT_MASK);
@@ -310,7 +328,7 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
 		return;
 
 	/*
-	 * The vtimer virtual interrupt is a 'mapped' interrupt, meaning part
+	 * If the timer virtual interrupt is a 'mapped' interrupt, part
 	 * of its lifecycle is offloaded to the hardware, and we therefore may
 	 * not have lowered the irq.level value before having to signal a new
 	 * interrupt, but have to signal an interrupt every time the level is
@@ -319,31 +337,55 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
 	level = kvm_timer_should_fire(vtimer);
 	kvm_timer_update_irq(vcpu, level, vtimer);
 
+	if (has_vhe()) {
+		level = kvm_timer_should_fire(ptimer);
+		kvm_timer_update_irq(vcpu, level, ptimer);
+
+		return;
+	}
+
 	phys_timer_emulate(vcpu);
 
 	if (kvm_timer_should_fire(ptimer) != ptimer->irq.level)
 		kvm_timer_update_irq(vcpu, !ptimer->irq.level, ptimer);
 }
 
-static void vtimer_save_state(struct kvm_vcpu *vcpu)
+static void timer_save_state(struct arch_timer_context *ctx)
 {
-	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
-	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
+	struct arch_timer_cpu *timer = vcpu_timer(ctx->vcpu);
+	enum kvm_arch_timers index = arch_timer_ctx_index(ctx);
 	unsigned long flags;
 
+	if (!timer->enabled)
+		return;
+
 	local_irq_save(flags);
 
 	if (timer->loaded == TIMER_NOT_LOADED)
 		goto out;
 
-	if (timer->enabled) {
-		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
-		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
-	}
+	switch (index) {
+	case TIMER_VTIMER:
+		ctx->cnt_ctl = read_sysreg_el0(cntv_ctl);
+		ctx->cnt_cval = read_sysreg_el0(cntv_cval);
 
-	/* Disable the virtual timer */
-	write_sysreg_el0(0, cntv_ctl);
-	isb();
+		/* Disable the timer */
+		write_sysreg_el0(0, cntv_ctl);
+		isb();
+
+		break;
+	case TIMER_PTIMER:
+		ctx->cnt_ctl = read_sysreg_el0(cntp_ctl);
+		ctx->cnt_cval = read_sysreg_el0(cntp_cval);
+
+		/* Disable the timer */
+		write_sysreg_el0(0, cntp_ctl);
+		isb();
+
+		break;
+	case NR_KVM_TIMERS:
+		break; /* GCC is braindead */
+	}
 
 	timer->loaded = TIMER_NOT_LOADED;
 out:
@@ -382,21 +424,33 @@ static void kvm_timer_unblocking(struct kvm_vcpu *vcpu)
 	soft_timer_cancel(&timer->bg_timer);
 }
 
-static void vtimer_restore_state(struct kvm_vcpu *vcpu)
+static void timer_restore_state(struct arch_timer_context *ctx)
 {
-	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
-	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
+	struct arch_timer_cpu *timer = vcpu_timer(ctx->vcpu);
+	enum kvm_arch_timers index = arch_timer_ctx_index(ctx);
 	unsigned long flags;
 
+	if (!timer->enabled)
+		return;
+
 	local_irq_save(flags);
 
 	if (timer->loaded == TIMER_EL1_LOADED)
 		goto out;
 
-	if (timer->enabled) {
-		write_sysreg_el0(vtimer->cnt_cval, cntv_cval);
+	switch (index) {
+	case TIMER_VTIMER:
+		write_sysreg_el0(ctx->cnt_cval, cntv_cval);
+		isb();
+		write_sysreg_el0(ctx->cnt_ctl, cntv_ctl);
+		break;
+	case TIMER_PTIMER:
+		write_sysreg_el0(ctx->cnt_cval, cntp_cval);
 		isb();
-		write_sysreg_el0(vtimer->cnt_ctl, cntv_ctl);
+		write_sysreg_el0(ctx->cnt_ctl, cntp_ctl);
+		break;
+	case NR_KVM_TIMERS:
+		break; /* GCC is braindead */
 	}
 
 	timer->loaded = TIMER_EL1_LOADED;
@@ -419,23 +473,23 @@ static void set_cntvoff(u64 cntvoff)
 	kvm_call_hyp(__kvm_timer_set_cntvoff, low, high);
 }
 
-static inline void set_vtimer_irq_phys_active(struct kvm_vcpu *vcpu, bool active)
+static inline void set_timer_irq_phys_active(struct arch_timer_context *ctx, bool active)
 {
 	int r;
-	r = irq_set_irqchip_state(host_vtimer_irq, IRQCHIP_STATE_ACTIVE, active);
+	r = irq_set_irqchip_state(ctx->host_timer_irq, IRQCHIP_STATE_ACTIVE, active);
 	WARN_ON(r);
 }
 
-static void kvm_timer_vcpu_load_gic(struct kvm_vcpu *vcpu)
+static void kvm_timer_vcpu_load_gic(struct arch_timer_context *ctx)
 {
-	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
+	struct kvm_vcpu *vcpu = ctx->vcpu;
 	bool phys_active;
 
 	if (irqchip_in_kernel(vcpu->kvm))
-		phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
+		phys_active = kvm_vgic_map_is_active(vcpu, ctx->irq.irq);
 	else
-		phys_active = vtimer->irq.level;
-	set_vtimer_irq_phys_active(vcpu, phys_active);
+		phys_active = ctx->irq.level;
+	set_timer_irq_phys_active(ctx, phys_active);
 }
 
 static void kvm_timer_vcpu_load_nogic(struct kvm_vcpu *vcpu)
@@ -467,14 +521,22 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
 	if (unlikely(!timer->enabled))
 		return;
 
-	if (static_branch_likely(&has_gic_active_state))
-		kvm_timer_vcpu_load_gic(vcpu);
-	else
+	if (static_branch_likely(&has_gic_active_state)) {
+		kvm_timer_vcpu_load_gic(vtimer);
+		if (has_vhe())
+			kvm_timer_vcpu_load_gic(ptimer);
+	} else {
 		kvm_timer_vcpu_load_nogic(vcpu);
+	}
 
 	set_cntvoff(vtimer->cntvoff);
 
-	vtimer_restore_state(vcpu);
+	timer_restore_state(vtimer);
+
+	if (has_vhe()) {
+		timer_restore_state(ptimer);
+		return;
+	}
 
 	/* Set the background timer for the physical timer emulation. */
 	phys_timer_emulate(vcpu);
@@ -506,12 +568,17 @@ bool kvm_timer_should_notify_user(struct kvm_vcpu *vcpu)
 void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
 {
 	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
+	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
 
 	if (unlikely(!timer->enabled))
 		return;
 
-	vtimer_save_state(vcpu);
+	timer_save_state(vtimer);
+	if (has_vhe()) {
+		timer_save_state(ptimer);
+		return;
+	}
 
 	/*
 	 * Cancel the physical timer emulation, because the only case where we
@@ -534,8 +601,7 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
 	 * counter of non-VHE case. For VHE, the virtual counter uses a fixed
 	 * virtual offset of zero, so no need to zero CNTVOFF_EL2 register.
 	 */
-	if (!has_vhe())
-		set_cntvoff(0);
+	set_cntvoff(0);
 }
 
 /*
@@ -550,7 +616,7 @@ static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu)
 	if (!kvm_timer_should_fire(vtimer)) {
 		kvm_timer_update_irq(vcpu, false, vtimer);
 		if (static_branch_likely(&has_gic_active_state))
-			set_vtimer_irq_phys_active(vcpu, false);
+			set_timer_irq_phys_active(vtimer, false);
 		else
 			enable_percpu_irq(host_vtimer_irq, host_vtimer_irq_flags);
 	}
@@ -625,7 +691,12 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
 	ptimer->hrtimer.function = kvm_phys_timer_expire;
 
 	vtimer->irq.irq = default_vtimer_irq.irq;
+	vtimer->host_timer_irq = host_vtimer_irq;
+	vtimer->host_timer_irq_flags = host_vtimer_irq_flags;
+
 	ptimer->irq.irq = default_ptimer_irq.irq;
+	ptimer->host_timer_irq = host_ptimer_irq;
+	ptimer->host_timer_irq_flags = host_ptimer_irq_flags;
 
 	vtimer->vcpu = vcpu;
 	ptimer->vcpu = vcpu;
@@ -634,6 +705,7 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
 static void kvm_timer_init_interrupt(void *info)
 {
 	enable_percpu_irq(host_vtimer_irq, host_vtimer_irq_flags);
+	enable_percpu_irq(host_ptimer_irq, host_ptimer_irq_flags);
 }
 
 int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
@@ -814,6 +886,8 @@ int kvm_timer_hyp_init(bool has_gic)
 		return -ENODEV;
 	}
 
+	/* First, do the virtual EL1 timer irq */
+
 	if (info->virtual_irq <= 0) {
 		kvm_err("kvm_arch_timer: invalid virtual timer IRQ: %d\n",
 			info->virtual_irq);
@@ -824,15 +898,15 @@ int kvm_timer_hyp_init(bool has_gic)
 	host_vtimer_irq_flags = irq_get_trigger_type(host_vtimer_irq);
 	if (host_vtimer_irq_flags != IRQF_TRIGGER_HIGH &&
 	    host_vtimer_irq_flags != IRQF_TRIGGER_LOW) {
-		kvm_err("Invalid trigger for IRQ%d, assuming level low\n",
+		kvm_err("Invalid trigger for vtimer IRQ%d, assuming level low\n",
 			host_vtimer_irq);
 		host_vtimer_irq_flags = IRQF_TRIGGER_LOW;
 	}
 
 	err = request_percpu_irq(host_vtimer_irq, kvm_arch_timer_handler,
-				 "kvm guest timer", kvm_get_running_vcpus());
+				 "kvm guest vtimer", kvm_get_running_vcpus());
 	if (err) {
-		kvm_err("kvm_arch_timer: can't request interrupt %d (%d)\n",
+		kvm_err("kvm_arch_timer: can't request vtimer interrupt %d (%d)\n",
 			host_vtimer_irq, err);
 		return err;
 	}
@@ -850,6 +924,38 @@ int kvm_timer_hyp_init(bool has_gic)
 
 	kvm_debug("virtual timer IRQ%d\n", host_vtimer_irq);
 
+	/* Now let's do the physical EL1 timer irq */
+
+	if (info->physical_irq > 0) {
+		host_ptimer_irq = info->physical_irq;
+		host_ptimer_irq_flags = irq_get_trigger_type(host_ptimer_irq);
+		if (host_ptimer_irq_flags != IRQF_TRIGGER_HIGH &&
+		    host_ptimer_irq_flags != IRQF_TRIGGER_LOW) {
+			kvm_err("Invalid trigger for ptimer IRQ%d, assuming level low\n",
+				host_ptimer_irq);
+			host_ptimer_irq_flags = IRQF_TRIGGER_LOW;
+		}
+
+		err = request_percpu_irq(host_ptimer_irq, kvm_arch_timer_handler,
+					 "kvm guest ptimer", kvm_get_running_vcpus());
+		if (err) {
+			kvm_err("kvm_arch_timer: can't request ptimer interrupt %d (%d)\n",
+				host_ptimer_irq, err);
+			return err;
+		}
+
+		if (has_gic) {
+			err = irq_set_vcpu_affinity(host_ptimer_irq,
+						    kvm_get_running_vcpus());
+			if (err) {
+				kvm_err("kvm_arch_timer: error setting vcpu affinity\n");
+				goto out_free_irq;
+			}
+		}
+
+		kvm_debug("physical timer IRQ%d\n", host_ptimer_irq);
+	}
+
 	cpuhp_setup_state(CPUHP_AP_KVM_ARM_TIMER_STARTING,
 			  "kvm/arm/timer:starting", kvm_timer_starting_cpu,
 			  kvm_timer_dying_cpu);
@@ -897,8 +1003,10 @@ bool kvm_arch_timer_get_input_level(int vintid)
 
 	if (vintid == vcpu_vtimer(vcpu)->irq.irq)
 		timer = vcpu_vtimer(vcpu);
+	else if (vintid == vcpu_ptimer(vcpu)->irq.irq)
+		timer = vcpu_ptimer(vcpu);
 	else
-		BUG(); /* We only map the vtimer so far */
+		BUG();
 
 	return kvm_timer_should_fire(timer);
 }
@@ -907,6 +1015,7 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
 {
 	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
 	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
+	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
 	int ret;
 
 	if (timer->enabled)
@@ -929,6 +1038,13 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
 	if (ret)
 		return ret;
 
+	if (has_vhe()) {
+		ret = kvm_vgic_map_phys_irq(vcpu, host_ptimer_irq, ptimer->irq.irq,
+					    kvm_arch_timer_get_input_level);
+		if (ret)
+			return ret;
+	}
+
 no_vgic:
 	timer->enabled = 1;
 	return 0;
@@ -951,7 +1067,7 @@ void kvm_timer_init_vhe(void)
 	 * Physical counter access is allowed.
 	 */
 	val = read_sysreg(cnthctl_el2);
-	val &= ~(CNTHCTL_EL1PCEN << cnthctl_shift);
+	val |= (CNTHCTL_EL1PCEN << cnthctl_shift);
 	val |= (CNTHCTL_EL1PCTEN << cnthctl_shift);
 	write_sysreg(val, cnthctl_el2);
 }
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 13/14] KVM: arm/arm64: Rework the timer code to use a timer_map
  2019-01-24 14:00 [PATCH 00/14] KVM: arm/arm64: Various rework in preparation of nested virt support Christoffer Dall
                   ` (11 preceding siblings ...)
  2019-01-24 14:00 ` [PATCH 12/14] KVM: arm/arm64: arch_timer: Assign the phys timer on VHE systems Christoffer Dall
@ 2019-01-24 14:00 ` Christoffer Dall
  2019-01-24 14:00 ` [PATCH 14/14] KVM: arm/arm64: Move kvm_is_write_fault to header file Christoffer Dall
  13 siblings, 0 replies; 33+ messages in thread
From: Christoffer Dall @ 2019-01-24 14:00 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, Christoffer Dall, kvm

We are currently emulating two timers in two different ways.  When we
add support for nested virtualization in the future, we are going to be
emulating either two timers in two diffferent ways, or four timers in a
single way.

We need a unified data structure to keep track of how we map virtual
state to physical state and we need to cleanup some of the timer code to
operate more independently on a struct arch_timer_context instead of
trying to consider the global state of the VCPU and recomputing all
state.

Co-written with Marc Zyngier <marc.zyngier@arm.com>

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
---
 include/kvm/arm_arch_timer.h |  22 +--
 virt/kvm/arm/arch_timer.c    | 295 +++++++++++++++++++----------------
 virt/kvm/arm/trace.h         | 105 +++++++++++++
 3 files changed, 276 insertions(+), 146 deletions(-)

diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index 722e0481f310..05a18dd265b5 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -51,14 +51,22 @@ struct arch_timer_context {
 	/* Emulated Timer (may be unused) */
 	struct hrtimer			hrtimer;
 
+	/*
+	 * We have multiple paths which can save/restore the timer state onto
+	 * the hardware, so we need some way of keeping track of where the
+	 * latest state is.
+	 */
+	bool				loaded;
+
 	/* Duplicated state from arch_timer.c for convenience */
 	u32				host_timer_irq;
 	u32				host_timer_irq_flags;
 };
 
-enum loaded_timer_state {
-	TIMER_NOT_LOADED,
-	TIMER_EL1_LOADED,
+struct timer_map {
+	struct arch_timer_context *direct_vtimer;
+	struct arch_timer_context *direct_ptimer;
+	struct arch_timer_context *emul_ptimer;
 };
 
 struct arch_timer_cpu {
@@ -69,14 +77,6 @@ struct arch_timer_cpu {
 
 	/* Is the timer enabled */
 	bool			enabled;
-
-	/*
-	 * We have multiple paths which can save/restore the timer state
-	 * onto the hardware, and for nested virt the EL1 hardware timers can
-	 * contain state from either the VM's EL1 timers or EL2 timers, so we
-	 * need some way of keeping track of where the latest state is.
-	 */
-	enum loaded_timer_state loaded;
 };
 
 int kvm_timer_hyp_init(bool);
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index eed8f48fbf9b..03d29f607355 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -68,6 +68,21 @@ u64 kvm_phys_timer_read(void)
 	return timecounter->cc->read(timecounter->cc);
 }
 
+static void get_timer_map(struct kvm_vcpu *vcpu, struct timer_map *map)
+{
+	if (has_vhe()) {
+		map->direct_vtimer = vcpu_vtimer(vcpu);
+		map->direct_ptimer = vcpu_ptimer(vcpu);
+		map->emul_ptimer = NULL;
+	} else {
+		map->direct_vtimer = vcpu_vtimer(vcpu);
+		map->direct_ptimer = NULL;
+		map->emul_ptimer = vcpu_ptimer(vcpu);
+	}
+
+	trace_kvm_get_timer_map(vcpu->vcpu_id, map);
+}
+
 static inline bool userspace_irqchip(struct kvm *kvm)
 {
 	return static_branch_unlikely(&userspace_irqchip_in_use) &&
@@ -89,6 +104,7 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
 {
 	struct kvm_vcpu *vcpu = *(struct kvm_vcpu **)dev_id;
 	struct arch_timer_context *ctx;
+	struct timer_map map;
 
 	/*
 	 * We may see a timer interrupt after vcpu_put() has been called which
@@ -99,10 +115,12 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
 	if (!vcpu)
 		return IRQ_HANDLED;
 
+	get_timer_map(vcpu, &map);
+
 	if (irq == host_vtimer_irq)
-		ctx = vcpu_vtimer(vcpu);
+		ctx = map.direct_vtimer;
 	else
-		ctx = vcpu_ptimer(vcpu);
+		ctx = map.direct_ptimer;
 
 	if (kvm_timer_should_fire(ctx))
 		kvm_timer_update_irq(vcpu, true, ctx);
@@ -136,7 +154,9 @@ static u64 kvm_timer_compute_delta(struct arch_timer_context *timer_ctx)
 
 static bool kvm_timer_irq_can_fire(struct arch_timer_context *timer_ctx)
 {
-	return !(timer_ctx->cnt_ctl & ARCH_TIMER_CTRL_IT_MASK) &&
+	WARN_ON(timer_ctx && timer_ctx->loaded);
+	return timer_ctx &&
+	       !(timer_ctx->cnt_ctl & ARCH_TIMER_CTRL_IT_MASK) &&
 		(timer_ctx->cnt_ctl & ARCH_TIMER_CTRL_ENABLE);
 }
 
@@ -146,21 +166,22 @@ static bool kvm_timer_irq_can_fire(struct arch_timer_context *timer_ctx)
  */
 static u64 kvm_timer_earliest_exp(struct kvm_vcpu *vcpu)
 {
-	u64 min_virt = ULLONG_MAX, min_phys = ULLONG_MAX;
-	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
-	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
+	u64 min_delta = ULLONG_MAX;
+	int i;
 
-	if (kvm_timer_irq_can_fire(vtimer))
-		min_virt = kvm_timer_compute_delta(vtimer);
+	for (i = 0; i < NR_KVM_TIMERS; i++) {
+		struct arch_timer_context *ctx = &vcpu->arch.timer_cpu.timers[i];
 
-	if (kvm_timer_irq_can_fire(ptimer))
-		min_phys = kvm_timer_compute_delta(ptimer);
+		WARN(ctx->loaded, "timer %d loaded\n", i);
+		if (kvm_timer_irq_can_fire(ctx))
+			min_delta = min(min_delta, kvm_timer_compute_delta(ctx));
+	}
 
 	/* If none of timers can fire, then return 0 */
-	if ((min_virt == ULLONG_MAX) && (min_phys == ULLONG_MAX))
+	if (min_delta == ULLONG_MAX)
 		return 0;
 
-	return min(min_virt, min_phys);
+	return min_delta;
 }
 
 static enum hrtimer_restart kvm_bg_timer_expire(struct hrtimer *hrt)
@@ -187,37 +208,45 @@ static enum hrtimer_restart kvm_bg_timer_expire(struct hrtimer *hrt)
 	return HRTIMER_NORESTART;
 }
 
-static enum hrtimer_restart kvm_phys_timer_expire(struct hrtimer *hrt)
+static enum hrtimer_restart kvm_hrtimer_expire(struct hrtimer *hrt)
 {
-	struct arch_timer_context *ptimer;
+	struct arch_timer_context *ctx;
 	struct kvm_vcpu *vcpu;
 	u64 ns;
 
-	ptimer = container_of(hrt, struct arch_timer_context, hrtimer);
-	vcpu = ptimer->vcpu;
+	ctx = container_of(hrt, struct arch_timer_context, hrtimer);
+	vcpu = ctx->vcpu;
+
+	trace_kvm_timer_hrtimer_expire(ctx);
 
 	/*
 	 * Check that the timer has really expired from the guest's
 	 * PoV (NTP on the host may have forced it to expire
 	 * early). If not ready, schedule for a later time.
 	 */
-	ns = kvm_timer_compute_delta(ptimer);
+	ns = kvm_timer_compute_delta(ctx);
 	if (unlikely(ns)) {
 		hrtimer_forward_now(hrt, ns_to_ktime(ns));
 		return HRTIMER_RESTART;
 	}
 
-	kvm_timer_update_irq(vcpu, true, ptimer);
+	kvm_timer_update_irq(vcpu, true, ctx);
 	return HRTIMER_NORESTART;
 }
 
 static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx)
 {
-	struct arch_timer_cpu *timer = vcpu_timer(timer_ctx->vcpu);
-	enum kvm_arch_timers index = arch_timer_ctx_index(timer_ctx);
+	struct arch_timer_cpu *timer;
+	enum kvm_arch_timers index;
 	u64 cval, now;
 
-	if (timer->loaded == TIMER_EL1_LOADED) {
+	if (!timer_ctx)
+		return false;
+
+	timer = vcpu_timer(timer_ctx->vcpu);
+	index = arch_timer_ctx_index(timer_ctx);
+
+	if (timer_ctx->loaded) {
 		u32 cnt_ctl = 0;
 
 		switch (index) {
@@ -249,13 +278,13 @@ static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx)
 
 bool kvm_timer_is_pending(struct kvm_vcpu *vcpu)
 {
-	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
-	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
+	struct timer_map map;
 
-	if (kvm_timer_should_fire(vtimer))
-		return true;
+	get_timer_map(vcpu, &map);
 
-	return kvm_timer_should_fire(ptimer);
+	return kvm_timer_should_fire(map.direct_vtimer) ||
+	       kvm_timer_should_fire(map.direct_ptimer) ||
+	       kvm_timer_should_fire(map.emul_ptimer);
 }
 
 /*
@@ -294,60 +323,28 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
 	}
 }
 
-/* Schedule the background timer for the emulated timer. */
-static void phys_timer_emulate(struct kvm_vcpu *vcpu)
+static void timer_emulate(struct arch_timer_context *ctx)
 {
-	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
+	bool should_fire = kvm_timer_should_fire(ctx);
 
-	/*
-	 * If the timer can fire now, we don't need to have a soft timer
-	 * scheduled for the future.  If the timer cannot fire at all,
-	 * then we also don't need a soft timer.
-	 */
-	if (kvm_timer_should_fire(ptimer) || !kvm_timer_irq_can_fire(ptimer)) {
-		soft_timer_cancel(&ptimer->hrtimer);
-		return;
-	}
-
-	soft_timer_start(&ptimer->hrtimer, kvm_timer_compute_delta(ptimer));
-}
-
-/*
- * Check if there was a change in the timer state, so that we should either
- * raise or lower the line level to the GIC or schedule a background timer to
- * emulate the physical timer.
- */
-static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
-{
-	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
-	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
-	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
-	bool level;
+	trace_kvm_timer_emulate(ctx, should_fire);
 
-	if (unlikely(!timer->enabled))
+	if (should_fire) {
+		kvm_timer_update_irq(ctx->vcpu, true, ctx);
 		return;
+	}
 
 	/*
-	 * If the timer virtual interrupt is a 'mapped' interrupt, part
-	 * of its lifecycle is offloaded to the hardware, and we therefore may
-	 * not have lowered the irq.level value before having to signal a new
-	 * interrupt, but have to signal an interrupt every time the level is
-	 * asserted.
+	 * If the timer can fire now, we don't need to have a soft timer
+	 * scheduled for the future.  If the timer cannot fire at all,
+	 * then we also don't need a soft timer.
 	 */
-	level = kvm_timer_should_fire(vtimer);
-	kvm_timer_update_irq(vcpu, level, vtimer);
-
-	if (has_vhe()) {
-		level = kvm_timer_should_fire(ptimer);
-		kvm_timer_update_irq(vcpu, level, ptimer);
-
+	if (!kvm_timer_irq_can_fire(ctx)) {
+		soft_timer_cancel(&ctx->hrtimer);
 		return;
 	}
 
-	phys_timer_emulate(vcpu);
-
-	if (kvm_timer_should_fire(ptimer) != ptimer->irq.level)
-		kvm_timer_update_irq(vcpu, !ptimer->irq.level, ptimer);
+	soft_timer_start(&ctx->hrtimer, kvm_timer_compute_delta(ctx));
 }
 
 static void timer_save_state(struct arch_timer_context *ctx)
@@ -361,7 +358,7 @@ static void timer_save_state(struct arch_timer_context *ctx)
 
 	local_irq_save(flags);
 
-	if (timer->loaded == TIMER_NOT_LOADED)
+	if (!ctx->loaded)
 		goto out;
 
 	switch (index) {
@@ -384,10 +381,12 @@ static void timer_save_state(struct arch_timer_context *ctx)
 
 		break;
 	case NR_KVM_TIMERS:
-		break; /* GCC is braindead */
+		BUG();
 	}
 
-	timer->loaded = TIMER_NOT_LOADED;
+	trace_kvm_timer_save_state(ctx);
+
+	ctx->loaded = false;
 out:
 	local_irq_restore(flags);
 }
@@ -400,14 +399,17 @@ static void timer_save_state(struct arch_timer_context *ctx)
 static void kvm_timer_blocking(struct kvm_vcpu *vcpu)
 {
 	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
-	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
-	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
+	struct timer_map map;
+
+	get_timer_map(vcpu, &map);
 
 	/*
-	 * If both timers are not capable of raising interrupts (disabled or
+	 * If no timers are capable of raising interrupts (disabled or
 	 * masked), then there's no more work for us to do.
 	 */
-	if (!kvm_timer_irq_can_fire(vtimer) && !kvm_timer_irq_can_fire(ptimer))
+	if (!kvm_timer_irq_can_fire(map.direct_vtimer) &&
+	    !kvm_timer_irq_can_fire(map.direct_ptimer) &&
+	    !kvm_timer_irq_can_fire(map.emul_ptimer))
 		return;
 
 	/*
@@ -435,7 +437,7 @@ static void timer_restore_state(struct arch_timer_context *ctx)
 
 	local_irq_save(flags);
 
-	if (timer->loaded == TIMER_EL1_LOADED)
+	if (ctx->loaded)
 		goto out;
 
 	switch (index) {
@@ -450,10 +452,12 @@ static void timer_restore_state(struct arch_timer_context *ctx)
 		write_sysreg_el0(ctx->cnt_ctl, cntp_ctl);
 		break;
 	case NR_KVM_TIMERS:
-		break; /* GCC is braindead */
+		BUG();
 	}
 
-	timer->loaded = TIMER_EL1_LOADED;
+	trace_kvm_timer_restore_state(ctx);
+
+	ctx->loaded = true;
 out:
 	local_irq_restore(flags);
 }
@@ -515,37 +519,31 @@ static void kvm_timer_vcpu_load_nogic(struct kvm_vcpu *vcpu)
 void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
 {
 	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
-	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
-	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
+	struct timer_map map;
 
 	if (unlikely(!timer->enabled))
 		return;
 
+	get_timer_map(vcpu, &map);
+
 	if (static_branch_likely(&has_gic_active_state)) {
-		kvm_timer_vcpu_load_gic(vtimer);
-		if (has_vhe())
-			kvm_timer_vcpu_load_gic(ptimer);
+		kvm_timer_vcpu_load_gic(map.direct_vtimer);
+		if (map.direct_ptimer)
+			kvm_timer_vcpu_load_gic(map.direct_ptimer);
 	} else {
 		kvm_timer_vcpu_load_nogic(vcpu);
 	}
 
-	set_cntvoff(vtimer->cntvoff);
-
-	timer_restore_state(vtimer);
-
-	if (has_vhe()) {
-		timer_restore_state(ptimer);
-		return;
-	}
-
-	/* Set the background timer for the physical timer emulation. */
-	phys_timer_emulate(vcpu);
+	set_cntvoff(map.direct_vtimer->cntvoff);
 
 	kvm_timer_unblocking(vcpu);
 
-	/* If the timer fired while we weren't running, inject it now */
-	if (kvm_timer_should_fire(ptimer) != ptimer->irq.level)
-		kvm_timer_update_irq(vcpu, !ptimer->irq.level, ptimer);
+	timer_restore_state(map.direct_vtimer);
+	if (map.direct_ptimer)
+		timer_restore_state(map.direct_ptimer);
+
+	if (map.emul_ptimer)
+		timer_emulate(map.emul_ptimer);
 }
 
 bool kvm_timer_should_notify_user(struct kvm_vcpu *vcpu)
@@ -568,20 +566,19 @@ bool kvm_timer_should_notify_user(struct kvm_vcpu *vcpu)
 void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
 {
 	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
-	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
-	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
+	struct timer_map map;
 
 	if (unlikely(!timer->enabled))
 		return;
 
-	timer_save_state(vtimer);
-	if (has_vhe()) {
-		timer_save_state(ptimer);
-		return;
-	}
+	get_timer_map(vcpu, &map);
+
+	timer_save_state(map.direct_vtimer);
+	if (map.direct_ptimer)
+		timer_save_state(map.direct_ptimer);
 
 	/*
-	 * Cancel the physical timer emulation, because the only case where we
+	 * Cancel soft timer emulation, because the only case where we
 	 * need it after a vcpu_put is in the context of a sleeping VCPU, and
 	 * in that case we already factor in the deadline for the physical
 	 * timer when scheduling the bg_timer.
@@ -589,7 +586,8 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
 	 * In any case, we re-schedule the hrtimer for the physical timer when
 	 * coming back to the VCPU thread in kvm_timer_vcpu_load().
 	 */
-	soft_timer_cancel(&ptimer->hrtimer);
+	if (map.emul_ptimer)
+		soft_timer_cancel(&map.emul_ptimer->hrtimer);
 
 	if (swait_active(kvm_arch_vcpu_wq(vcpu)))
 		kvm_timer_blocking(vcpu);
@@ -636,8 +634,9 @@ void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
 int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu)
 {
 	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
-	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
-	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
+	struct timer_map map;
+
+	get_timer_map(vcpu, &map);
 
 	/*
 	 * The bits in CNTV_CTL are architecturally reset to UNKNOWN for ARMv8
@@ -645,12 +644,22 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu)
 	 * resets the timer to be disabled and unmasked and is compliant with
 	 * the ARMv7 architecture.
 	 */
-	vtimer->cnt_ctl = 0;
-	ptimer->cnt_ctl = 0;
-	kvm_timer_update_state(vcpu);
+	vcpu_vtimer(vcpu)->cnt_ctl = 0;
+	vcpu_ptimer(vcpu)->cnt_ctl = 0;
+
+	if (timer->enabled) {
+		kvm_timer_update_irq(vcpu, false, vcpu_vtimer(vcpu));
+		kvm_timer_update_irq(vcpu, false, vcpu_ptimer(vcpu));
+
+		if (irqchip_in_kernel(vcpu->kvm)) {
+			kvm_vgic_reset_mapped_irq(vcpu, map.direct_vtimer->irq.irq);
+			if (map.direct_ptimer)
+				kvm_vgic_reset_mapped_irq(vcpu, map.direct_ptimer->irq.irq);
+		}
+	}
 
-	if (timer->enabled && irqchip_in_kernel(vcpu->kvm))
-		kvm_vgic_reset_mapped_irq(vcpu, vtimer->irq.irq);
+	if (map.emul_ptimer)
+		soft_timer_cancel(&map.emul_ptimer->hrtimer);
 
 	return 0;
 }
@@ -687,15 +696,18 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
 	hrtimer_init(&timer->bg_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
 	timer->bg_timer.function = kvm_bg_timer_expire;
 
+	hrtimer_init(&vtimer->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
 	hrtimer_init(&ptimer->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
-	ptimer->hrtimer.function = kvm_phys_timer_expire;
+	vtimer->hrtimer.function = kvm_hrtimer_expire;
+	ptimer->hrtimer.function = kvm_hrtimer_expire;
 
 	vtimer->irq.irq = default_vtimer_irq.irq;
-	vtimer->host_timer_irq = host_vtimer_irq;
-	vtimer->host_timer_irq_flags = host_vtimer_irq_flags;
-
 	ptimer->irq.irq = default_ptimer_irq.irq;
+
+	vtimer->host_timer_irq = host_vtimer_irq;
 	ptimer->host_timer_irq = host_ptimer_irq;
+
+	vtimer->host_timer_irq_flags = host_vtimer_irq_flags;
 	ptimer->host_timer_irq_flags = host_ptimer_irq_flags;
 
 	vtimer->vcpu = vcpu;
@@ -710,32 +722,39 @@ static void kvm_timer_init_interrupt(void *info)
 
 int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
 {
+	struct arch_timer_context *timer;
+	bool level;
+
 	switch (regid) {
 	case KVM_REG_ARM_TIMER_CTL:
-		kvm_arm_timer_write(vcpu,
-				    vcpu_vtimer(vcpu), TIMER_REG_CTL, value);
+		timer = vcpu_vtimer(vcpu);
+		kvm_arm_timer_write(vcpu, timer, TIMER_REG_CTL, value);
 		break;
 	case KVM_REG_ARM_TIMER_CNT:
+		timer = vcpu_vtimer(vcpu);
 		update_vtimer_cntvoff(vcpu, kvm_phys_timer_read() - value);
 		break;
 	case KVM_REG_ARM_TIMER_CVAL:
-		kvm_arm_timer_write(vcpu,
-				    vcpu_vtimer(vcpu), TIMER_REG_CVAL, value);
+		timer = vcpu_vtimer(vcpu);
+		kvm_arm_timer_write(vcpu, timer, TIMER_REG_CVAL, value);
 		break;
 	case KVM_REG_ARM_PTIMER_CTL:
-		kvm_arm_timer_write(vcpu,
-				    vcpu_ptimer(vcpu), TIMER_REG_CTL, value);
+		timer = vcpu_ptimer(vcpu);
+		kvm_arm_timer_write(vcpu, timer, TIMER_REG_CTL, value);
 		break;
 	case KVM_REG_ARM_PTIMER_CVAL:
-		kvm_arm_timer_write(vcpu,
-				    vcpu_ptimer(vcpu), TIMER_REG_CVAL, value);
+		timer = vcpu_ptimer(vcpu);
+		kvm_arm_timer_write(vcpu, timer, TIMER_REG_CVAL, value);
 		break;
 
 	default:
 		return -1;
 	}
 
-	kvm_timer_update_state(vcpu);
+	level = kvm_timer_should_fire(timer);
+	kvm_timer_update_irq(vcpu, level, timer);
+	timer_emulate(timer);
+
 	return 0;
 }
 
@@ -1014,8 +1033,7 @@ bool kvm_arch_timer_get_input_level(int vintid)
 int kvm_timer_enable(struct kvm_vcpu *vcpu)
 {
 	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
-	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
-	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
+	struct timer_map map;
 	int ret;
 
 	if (timer->enabled)
@@ -1033,18 +1051,25 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
 		return -EINVAL;
 	}
 
-	ret = kvm_vgic_map_phys_irq(vcpu, host_vtimer_irq, vtimer->irq.irq,
+	get_timer_map(vcpu, &map);
+
+	ret = kvm_vgic_map_phys_irq(vcpu,
+				    map.direct_vtimer->host_timer_irq,
+				    map.direct_vtimer->irq.irq,
 				    kvm_arch_timer_get_input_level);
 	if (ret)
 		return ret;
 
-	if (has_vhe()) {
-		ret = kvm_vgic_map_phys_irq(vcpu, host_ptimer_irq, ptimer->irq.irq,
+	if (map.direct_ptimer) {
+		ret = kvm_vgic_map_phys_irq(vcpu,
+					    map.direct_ptimer->host_timer_irq,
+					    map.direct_ptimer->irq.irq,
 					    kvm_arch_timer_get_input_level);
-		if (ret)
-			return ret;
 	}
 
+	if (ret)
+		return ret;
+
 no_vgic:
 	timer->enabled = 1;
 	return 0;
diff --git a/virt/kvm/arm/trace.h b/virt/kvm/arm/trace.h
index 3828beab93f2..54bb059243b9 100644
--- a/virt/kvm/arm/trace.h
+++ b/virt/kvm/arm/trace.h
@@ -2,6 +2,7 @@
 #if !defined(_TRACE_KVM_H) || defined(TRACE_HEADER_MULTI_READ)
 #define _TRACE_KVM_H
 
+#include <kvm/arm_arch_timer.h>
 #include <linux/tracepoint.h>
 
 #undef TRACE_SYSTEM
@@ -262,6 +263,110 @@ TRACE_EVENT(kvm_timer_update_irq,
 		  __entry->vcpu_id, __entry->irq, __entry->level)
 );
 
+TRACE_EVENT(kvm_get_timer_map,
+	TP_PROTO(unsigned long vcpu_id, struct timer_map *map),
+	TP_ARGS(vcpu_id, map),
+
+	TP_STRUCT__entry(
+		__field(	unsigned long,		vcpu_id	)
+		__field(	int,			direct_vtimer	)
+		__field(	int,			direct_ptimer	)
+		__field(	int,			emul_ptimer	)
+	),
+
+	TP_fast_assign(
+		__entry->vcpu_id		= vcpu_id;
+		__entry->direct_vtimer		= arch_timer_ctx_index(map->direct_vtimer);
+		__entry->direct_ptimer =
+			(map->direct_ptimer) ? arch_timer_ctx_index(map->direct_ptimer) : -1;
+		__entry->emul_ptimer =
+			(map->emul_ptimer) ? arch_timer_ctx_index(map->emul_ptimer) : -1;
+	),
+
+	TP_printk("VCPU: %ld, dv: %d, dp: %d, ep: %d",
+		  __entry->vcpu_id,
+		  __entry->direct_vtimer,
+		  __entry->direct_ptimer,
+		  __entry->emul_ptimer)
+);
+
+TRACE_EVENT(kvm_timer_save_state,
+	TP_PROTO(struct arch_timer_context *ctx),
+	TP_ARGS(ctx),
+
+	TP_STRUCT__entry(
+		__field(	unsigned long,		ctl		)
+		__field(	unsigned long long,	cval		)
+		__field(	int,			timer_idx	)
+	),
+
+	TP_fast_assign(
+		__entry->ctl			= ctx->cnt_ctl;
+		__entry->cval			= ctx->cnt_cval;
+		__entry->timer_idx		= arch_timer_ctx_index(ctx);
+	),
+
+	TP_printk("   CTL: %#08lx CVAL: %#16llx arch_timer_ctx_index: %d",
+		  __entry->ctl,
+		  __entry->cval,
+		  __entry->timer_idx)
+);
+
+TRACE_EVENT(kvm_timer_restore_state,
+	TP_PROTO(struct arch_timer_context *ctx),
+	TP_ARGS(ctx),
+
+	TP_STRUCT__entry(
+		__field(	unsigned long,		ctl		)
+		__field(	unsigned long long,	cval		)
+		__field(	int,			timer_idx	)
+	),
+
+	TP_fast_assign(
+		__entry->ctl			= ctx->cnt_ctl;
+		__entry->cval			= ctx->cnt_cval;
+		__entry->timer_idx		= arch_timer_ctx_index(ctx);
+	),
+
+	TP_printk("CTL: %#08lx CVAL: %#16llx arch_timer_ctx_index: %d",
+		  __entry->ctl,
+		  __entry->cval,
+		  __entry->timer_idx)
+);
+
+TRACE_EVENT(kvm_timer_hrtimer_expire,
+	TP_PROTO(struct arch_timer_context *ctx),
+	TP_ARGS(ctx),
+
+	TP_STRUCT__entry(
+		__field(	int,			timer_idx	)
+	),
+
+	TP_fast_assign(
+		__entry->timer_idx		= arch_timer_ctx_index(ctx);
+	),
+
+	TP_printk("arch_timer_ctx_index: %d", __entry->timer_idx)
+);
+
+TRACE_EVENT(kvm_timer_emulate,
+	TP_PROTO(struct arch_timer_context *ctx, bool should_fire),
+	TP_ARGS(ctx, should_fire),
+
+	TP_STRUCT__entry(
+		__field(	int,			timer_idx	)
+		__field(	bool,			should_fire	)
+	),
+
+	TP_fast_assign(
+		__entry->timer_idx		= arch_timer_ctx_index(ctx);
+		__entry->should_fire		= should_fire;
+	),
+
+	TP_printk("arch_timer_ctx_index: %d (should_fire: %d)",
+		  __entry->timer_idx, __entry->should_fire)
+);
+
 #endif /* _TRACE_KVM_H */
 
 #undef TRACE_INCLUDE_PATH
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 14/14] KVM: arm/arm64: Move kvm_is_write_fault to header file
  2019-01-24 14:00 [PATCH 00/14] KVM: arm/arm64: Various rework in preparation of nested virt support Christoffer Dall
                   ` (12 preceding siblings ...)
  2019-01-24 14:00 ` [PATCH 13/14] KVM: arm/arm64: Rework the timer code to use a timer_map Christoffer Dall
@ 2019-01-24 14:00 ` Christoffer Dall
  13 siblings, 0 replies; 33+ messages in thread
From: Christoffer Dall @ 2019-01-24 14:00 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, Christoffer Dall, kvm

From: Christoffer Dall <christoffer.dall@linaro.org>

Move this little function to the header files for arm/arm64 so other
code can make use of it directly.

Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
---
 arch/arm/include/asm/kvm_emulate.h   | 8 ++++++++
 arch/arm64/include/asm/kvm_emulate.h | 8 ++++++++
 virt/kvm/arm/mmu.c                   | 8 --------
 3 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h
index 77121b713bef..8927cae7c966 100644
--- a/arch/arm/include/asm/kvm_emulate.h
+++ b/arch/arm/include/asm/kvm_emulate.h
@@ -265,6 +265,14 @@ static inline bool kvm_vcpu_dabt_isextabt(struct kvm_vcpu *vcpu)
 	}
 }
 
+static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
+{
+	if (kvm_vcpu_trap_is_iabt(vcpu))
+		return false;
+
+	return kvm_vcpu_dabt_iswrite(vcpu);
+}
+
 static inline u32 kvm_vcpu_hvc_get_imm(struct kvm_vcpu *vcpu)
 {
 	return kvm_vcpu_get_hsr(vcpu) & HSR_HVC_IMM_MASK;
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 506386a3edde..a0d1ce9ae12b 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -331,6 +331,14 @@ static inline int kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
 	return ESR_ELx_SYS64_ISS_RT(esr);
 }
 
+static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
+{
+	if (kvm_vcpu_trap_is_iabt(vcpu))
+		return false;
+
+	return kvm_vcpu_dabt_iswrite(vcpu);
+}
+
 static inline unsigned long kvm_vcpu_get_mpidr_aff(struct kvm_vcpu *vcpu)
 {
 	return vcpu_read_sys_reg(vcpu, MPIDR_EL1) & MPIDR_HWID_BITMASK;
diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
index bffcbc423f4c..c17010bc33a9 100644
--- a/virt/kvm/arm/mmu.c
+++ b/virt/kvm/arm/mmu.c
@@ -1398,14 +1398,6 @@ static bool transparent_hugepage_adjust(kvm_pfn_t *pfnp, phys_addr_t *ipap)
 	return false;
 }
 
-static bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
-{
-	if (kvm_vcpu_trap_is_iabt(vcpu))
-		return false;
-
-	return kvm_vcpu_dabt_iswrite(vcpu);
-}
-
 /**
  * stage2_wp_ptes - write protect PMD range
  * @pmd:	pointer to pmd entry
-- 
2.18.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 06/14] KVM: arm/arm64: Factor out VMID into struct kvm_vmid
  2019-01-24 14:00 ` [PATCH 06/14] KVM: arm/arm64: Factor out VMID into struct kvm_vmid Christoffer Dall
@ 2019-01-24 19:01   ` James Morse
  2019-01-25 10:09     ` Marc Zyngier
  2019-01-25 11:05   ` Julien Thierry
  2019-02-21 11:02   ` Julien Grall
  2 siblings, 1 reply; 33+ messages in thread
From: James Morse @ 2019-01-24 19:01 UTC (permalink / raw)
  To: Christoffer Dall
  Cc: Marc Zyngier, Suzuki K Poulose, kvmarm, linux-arm-kernel, kvm

Hi guys,

(CC: +Suzuki)

On 24/01/2019 14:00, Christoffer Dall wrote:
> In preparation for nested virtualization where we are going to have more
> than a single VMID per VM, let's factor out the VMID data into a
> separate VMID data structure and change the VMID allocator to operate on
> this new structure instead of using a struct kvm.
> 
> This also means that udate_vttbr now becomes update_vmid, and that the
> vttbr itself is generated on the fly based on the stage 2 page table
> base address and the vmid.
> 
> We cache the physical address of the pgd when allocating the pgd to
> avoid doing the calculation on every entry to the guest and to avoid
> calling into potentially non-hyp-mapped code from hyp/EL2.
> 
> If we wanted to merge the VMID allocator with the arm64 ASID allocator
> at some point in the future, it should actually become easier to do that
> after this patch.

> Note that to avoid mapping the kvm_vmid_bits variable into hyp, we
> simply forego the masking of the vmid value in kvm_get_vttbr and rely on
> update_vmid to always assign a valid vmid value (within the supported
> range).


> diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> index 8af4b1befa42..189d93461d33 100644
> --- a/arch/arm64/include/asm/kvm_mmu.h
> +++ b/arch/arm64/include/asm/kvm_mmu.h
> @@ -596,5 +596,16 @@ static inline bool kvm_cpu_has_cnp(void)
>  	return system_supports_cnp();
>  }
>  
> +static __always_inline u64 kvm_get_vttbr(struct kvm *kvm)
> +{
> +	struct kvm_vmid *vmid = &kvm->arch.vmid;
> +	u64 vmid_field, baddr;
> +	u64 cnp = kvm_cpu_has_cnp() ? VTTBR_CNP_BIT : 0;
> +
> +	baddr = kvm->arch.pgd_phys;
> +	vmid_field = (u64)vmid->vmid << VTTBR_VMID_SHIFT;
> +	return kvm_phys_to_vttbr(baddr) | vmid_field | cnp;
> +}

(32bits version is the same ... but I guess there is nowhere to put it!)


> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> index 3dd240ea9e76..b77db673bb03 100644
> --- a/virt/kvm/arm/arm.c
> +++ b/virt/kvm/arm/arm.c
> @@ -536,18 +529,12 @@ static void update_vttbr(struct kvm *kvm)
>  		kvm_call_hyp(__kvm_flush_vm_context);
>  	}
>  
> -	kvm->arch.vmid = kvm_next_vmid;
> +	vmid->vmid = kvm_next_vmid;
>  	kvm_next_vmid++;
> -	kvm_next_vmid &= (1 << kvm_vmid_bits) - 1;
> -
> -	/* update vttbr to be used with the new vmid */
> -	pgd_phys = virt_to_phys(kvm->arch.pgd);

> -	BUG_ON(pgd_phys & ~kvm_vttbr_baddr_mask(kvm));

Where did this go? (escaped during a turbulent rebase?)

This removes the only caller of kvm_vttbr_baddr_mask()... It looks like this is
a safety check that the stage2-pgd is correctly aligned when the IPA size, and
thus size of the top level entry can by set by user-space.

... or is it unnecessary if alloc_pages_exact() can only return naturally
aligned groups of pages? (which I haven't checked)

Keeping it sounds like a good thing to have in case we accidentally merge
stage2/host-stage1 pgd's somewhere down the line.

(Suzuki suggested it would make more sense in kvm_alloc_stage2_pgd(), where we
could fail vm creation, instead of BUG()ing).

(this was added by e55cac5bf2a9c ("kvm: arm/arm64: Prepare for VM specific
stage2 translations"), the bulk of the logic is in 595583306434c ("kvm: arm64:
Dynamic configuration of VTTBR mask"))


> -	vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & VTTBR_VMID_MASK(kvm_vmid_bits);
> -	kvm->arch.vttbr = kvm_phys_to_vttbr(pgd_phys) | vmid | cnp;
> +	kvm_next_vmid &= (1 << kvm_get_vmid_bits()) - 1;
>  
>  	smp_wmb();
> -	WRITE_ONCE(kvm->arch.vmid_gen, atomic64_read(&kvm_vmid_gen));
> +	WRITE_ONCE(vmid->vmid_gen, atomic64_read(&kvm_vmid_gen));
>  
>  	spin_unlock(&kvm_vmid_lock);
>  }


Thanks,

James

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 06/14] KVM: arm/arm64: Factor out VMID into struct kvm_vmid
  2019-01-24 19:01   ` James Morse
@ 2019-01-25 10:09     ` Marc Zyngier
  0 siblings, 0 replies; 33+ messages in thread
From: Marc Zyngier @ 2019-01-25 10:09 UTC (permalink / raw)
  To: James Morse
  Cc: kvm, Suzuki K Poulose, Christoffer Dall, linux-arm-kernel, kvmarm

Hi James,

Thanks for looking into this.

On Thu, 24 Jan 2019 19:01:57 +0000,
James Morse <james.morse@arm.com> wrote:
> 
> Hi guys,
> 
> (CC: +Suzuki)
> 
> On 24/01/2019 14:00, Christoffer Dall wrote:
> > In preparation for nested virtualization where we are going to have more
> > than a single VMID per VM, let's factor out the VMID data into a
> > separate VMID data structure and change the VMID allocator to operate on
> > this new structure instead of using a struct kvm.
> > 
> > This also means that udate_vttbr now becomes update_vmid, and that the
> > vttbr itself is generated on the fly based on the stage 2 page table
> > base address and the vmid.
> > 
> > We cache the physical address of the pgd when allocating the pgd to
> > avoid doing the calculation on every entry to the guest and to avoid
> > calling into potentially non-hyp-mapped code from hyp/EL2.
> > 
> > If we wanted to merge the VMID allocator with the arm64 ASID allocator
> > at some point in the future, it should actually become easier to do that
> > after this patch.
> 
> > Note that to avoid mapping the kvm_vmid_bits variable into hyp, we
> > simply forego the masking of the vmid value in kvm_get_vttbr and rely on
> > update_vmid to always assign a valid vmid value (within the supported
> > range).
> 
> 
> > diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> > index 8af4b1befa42..189d93461d33 100644
> > --- a/arch/arm64/include/asm/kvm_mmu.h
> > +++ b/arch/arm64/include/asm/kvm_mmu.h
> > @@ -596,5 +596,16 @@ static inline bool kvm_cpu_has_cnp(void)
> >  	return system_supports_cnp();
> >  }
> >  
> > +static __always_inline u64 kvm_get_vttbr(struct kvm *kvm)
> > +{
> > +	struct kvm_vmid *vmid = &kvm->arch.vmid;
> > +	u64 vmid_field, baddr;
> > +	u64 cnp = kvm_cpu_has_cnp() ? VTTBR_CNP_BIT : 0;
> > +
> > +	baddr = kvm->arch.pgd_phys;
> > +	vmid_field = (u64)vmid->vmid << VTTBR_VMID_SHIFT;
> > +	return kvm_phys_to_vttbr(baddr) | vmid_field | cnp;
> > +}
> 
> (32bits version is the same ... but I guess there is nowhere to put it!)

Yes, that's the usual conundrum.

> 
> 
> > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > index 3dd240ea9e76..b77db673bb03 100644
> > --- a/virt/kvm/arm/arm.c
> > +++ b/virt/kvm/arm/arm.c
> > @@ -536,18 +529,12 @@ static void update_vttbr(struct kvm *kvm)
> >  		kvm_call_hyp(__kvm_flush_vm_context);
> >  	}
> >  
> > -	kvm->arch.vmid = kvm_next_vmid;
> > +	vmid->vmid = kvm_next_vmid;
> >  	kvm_next_vmid++;
> > -	kvm_next_vmid &= (1 << kvm_vmid_bits) - 1;
> > -
> > -	/* update vttbr to be used with the new vmid */
> > -	pgd_phys = virt_to_phys(kvm->arch.pgd);
> 
> > -	BUG_ON(pgd_phys & ~kvm_vttbr_baddr_mask(kvm));
> 
> Where did this go? (escaped during a turbulent rebase?)
> 
> This removes the only caller of kvm_vttbr_baddr_mask()... It looks
> like this is a safety check that the stage2-pgd is correctly aligned
> when the IPA size, and thus size of the top level entry can by set
> by user-space.
> 
> ... or is it unnecessary if alloc_pages_exact() can only return naturally
> aligned groups of pages? (which I haven't checked)

The rational is indeed that alloc_pages_exact allocates a power of 2
number of pages, and then frees the unrequested tail pages. This means
that we're always correctly aligned.

> Keeping it sounds like a good thing to have in case we accidentally merge
> stage2/host-stage1 pgd's somewhere down the line.

This seems hard to achieve for this very reason, as level-0
concatenation gets in the way of unifying the two allocators.

> (Suzuki suggested it would make more sense in kvm_alloc_stage2_pgd(), where we
> could fail vm creation, instead of BUG()ing).
> 
> (this was added by e55cac5bf2a9c ("kvm: arm/arm64: Prepare for VM specific
> stage2 translations"), the bulk of the logic is in 595583306434c ("kvm: arm64:
> Dynamic configuration of VTTBR mask"))

We could bring it back if people have a strong feeling about this, but
certainly not as a BUG_ON(). Failing it in gracefully in
kvm_alloc_stage2_pgd seems a more palatable solution, but I can't
convince myself that we need it.

Thanks,

	M.

-- 
Jazz is not dead, it just smell funny.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 06/14] KVM: arm/arm64: Factor out VMID into struct kvm_vmid
  2019-01-24 14:00 ` [PATCH 06/14] KVM: arm/arm64: Factor out VMID into struct kvm_vmid Christoffer Dall
  2019-01-24 19:01   ` James Morse
@ 2019-01-25 11:05   ` Julien Thierry
  2019-01-31 13:01     ` Marc Zyngier
  2019-02-21 11:02   ` Julien Grall
  2 siblings, 1 reply; 33+ messages in thread
From: Julien Thierry @ 2019-01-25 11:05 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, kvm

Hi Christoffer,

On 24/01/2019 14:00, Christoffer Dall wrote:
> In preparation for nested virtualization where we are going to have more
> than a single VMID per VM, let's factor out the VMID data into a
> separate VMID data structure and change the VMID allocator to operate on
> this new structure instead of using a struct kvm.
> 
> This also means that udate_vttbr now becomes update_vmid, and that the
> vttbr itself is generated on the fly based on the stage 2 page table
> base address and the vmid.
> 
> We cache the physical address of the pgd when allocating the pgd to
> avoid doing the calculation on every entry to the guest and to avoid
> calling into potentially non-hyp-mapped code from hyp/EL2.
> 
> If we wanted to merge the VMID allocator with the arm64 ASID allocator
> at some point in the future, it should actually become easier to do that
> after this patch.
> 
> Note that to avoid mapping the kvm_vmid_bits variable into hyp, we
> simply forego the masking of the vmid value in kvm_get_vttbr and rely on
> update_vmid to always assign a valid vmid value (within the supported
> range).
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  arch/arm/include/asm/kvm_host.h   | 13 ++++---
>  arch/arm/include/asm/kvm_mmu.h    | 11 ++++++
>  arch/arm/kvm/hyp/switch.c         |  2 +-
>  arch/arm/kvm/hyp/tlb.c            |  4 +--
>  arch/arm64/include/asm/kvm_host.h |  9 +++--
>  arch/arm64/include/asm/kvm_hyp.h  |  3 +-
>  arch/arm64/include/asm/kvm_mmu.h  | 11 ++++++
>  virt/kvm/arm/arm.c                | 57 +++++++++++--------------------
>  virt/kvm/arm/mmu.c                |  2 ++
>  9 files changed, 63 insertions(+), 49 deletions(-)
> 

[...]

> diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
> index 3a875fc1b63c..fadbd9ad3a90 100644
> --- a/arch/arm/include/asm/kvm_mmu.h
> +++ b/arch/arm/include/asm/kvm_mmu.h
> @@ -426,6 +426,17 @@ static inline bool kvm_cpu_has_cnp(void)
>  	return false;
>  }
>  
> +static __always_inline u64 kvm_get_vttbr(struct kvm *kvm)
> +{
> +	struct kvm_vmid *vmid = &kvm->arch.vmid;
> +	u64 vmid_field, baddr;
> +	u64 cnp = kvm_cpu_has_cnp() ? VTTBR_CNP_BIT : 0;
> +

Nit:
As James pointed out, we're not merging this one with the 64-bit
version. The question is, since we don't merge it, can't we simplify
this one by removing the CNP related code from it? (we know CNP is
always false for 32-bit ARM).

> +	baddr = kvm->arch.pgd_phys;
> +	vmid_field = (u64)vmid->vmid << VTTBR_VMID_SHIFT;
> +	return kvm_phys_to_vttbr(baddr) | vmid_field | cnp;
> +}
> +
>  #endif	/* !__ASSEMBLY__ */

Otherwise, things look good to me:

Reviewed-by: Julien Thierry <julien.thierry@arm.com>

Cheers,

-- 
Julien Thierry

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 10/14] KVM: arm/arm64: consolidate arch timer trap handlers
  2019-01-24 14:00 ` [PATCH 10/14] KVM: arm/arm64: consolidate arch timer trap handlers Christoffer Dall
@ 2019-01-25 12:33   ` Julien Thierry
  2019-01-30 17:38     ` Marc Zyngier
  0 siblings, 1 reply; 33+ messages in thread
From: Julien Thierry @ 2019-01-25 12:33 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel
  Cc: Marc Zyngier, Andre Przywara, kvm

Hi,

I'm wondering, could this patch be split in two? One for the
introduction of kvm_arm_timer_read_sysreg() +
kvm_arm_timer_write_sysreg() and the other for merging the handlers into
a single function?



On 24/01/2019 14:00, Christoffer Dall wrote:
> From: Andre Przywara <andre.przywara@arm.com>
> 
> At the moment we have separate system register emulation handlers for
> each timer register. Actually they are quite similar, and we rely on
> kvm_arm_timer_[gs]et_reg() for the actual emulation anyways, so let's
> just merge all of those handlers into one function, which just marshalls
> the arguments and then hands off to a set of common accessors.
> This makes extending the emulation to include EL2 timers much easier.
> 
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> [Fixed 32-bit VM breakage and reduced to reworking existing code]
> Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
> [Fixed 32bit host, general cleanup]
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  arch/arm/kvm/coproc.c           |  23 +++---
>  arch/arm64/include/asm/sysreg.h |   4 +
>  arch/arm64/kvm/sys_regs.c       |  80 +++++++++++---------
>  include/kvm/arm_arch_timer.h    |  23 ++++++
>  virt/kvm/arm/arch_timer.c       | 129 +++++++++++++++++++++++++++-----
>  5 files changed, 196 insertions(+), 63 deletions(-)
> 
> diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
> index 222c1635bc7a..51863364f8d1 100644
> --- a/arch/arm/kvm/coproc.c
> +++ b/arch/arm/kvm/coproc.c
> @@ -293,15 +293,16 @@ static bool access_cntp_tval(struct kvm_vcpu *vcpu,
>  			     const struct coproc_params *p,
>  			     const struct coproc_reg *r)
>  {
> -	u64 now = kvm_phys_timer_read();
> -	u64 val;
> +	u32 val;
>  
>  	if (p->is_write) {
>  		val = *vcpu_reg(vcpu, p->Rt1);
> -		kvm_arm_timer_set_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL, val + now);
> +		kvm_arm_timer_write_sysreg(vcpu,
> +					   TIMER_PTIMER, TIMER_REG_TVAL, val);
>  	} else {
> -		val = kvm_arm_timer_get_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL);
> -		*vcpu_reg(vcpu, p->Rt1) = val - now;
> +		val = kvm_arm_timer_read_sysreg(vcpu,
> +						TIMER_PTIMER, TIMER_REG_TVAL);
> +		*vcpu_reg(vcpu, p->Rt1) = val;
>  	}
>  
>  	return true;
> @@ -315,9 +316,11 @@ static bool access_cntp_ctl(struct kvm_vcpu *vcpu,
>  
>  	if (p->is_write) {
>  		val = *vcpu_reg(vcpu, p->Rt1);
> -		kvm_arm_timer_set_reg(vcpu, KVM_REG_ARM_PTIMER_CTL, val);
> +		kvm_arm_timer_write_sysreg(vcpu,
> +					   TIMER_PTIMER, TIMER_REG_CTL, val);
>  	} else {
> -		val = kvm_arm_timer_get_reg(vcpu, KVM_REG_ARM_PTIMER_CTL);
> +		val = kvm_arm_timer_read_sysreg(vcpu,
> +						TIMER_PTIMER, TIMER_REG_CTL);
>  		*vcpu_reg(vcpu, p->Rt1) = val;
>  	}
>  
> @@ -333,9 +336,11 @@ static bool access_cntp_cval(struct kvm_vcpu *vcpu,
>  	if (p->is_write) {
>  		val = (u64)*vcpu_reg(vcpu, p->Rt2) << 32;
>  		val |= *vcpu_reg(vcpu, p->Rt1);
> -		kvm_arm_timer_set_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL, val);
> +		kvm_arm_timer_write_sysreg(vcpu,
> +					   TIMER_PTIMER, TIMER_REG_CVAL, val);
>  	} else {
> -		val = kvm_arm_timer_get_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL);
> +		val = kvm_arm_timer_read_sysreg(vcpu,
> +						TIMER_PTIMER, TIMER_REG_CVAL);
>  		*vcpu_reg(vcpu, p->Rt1) = val;
>  		*vcpu_reg(vcpu, p->Rt2) = val >> 32;
>  	}
> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
> index 3e5650903d6d..6482e8bcf1b8 100644
> --- a/arch/arm64/include/asm/sysreg.h
> +++ b/arch/arm64/include/asm/sysreg.h
> @@ -392,6 +392,10 @@
>  #define SYS_CNTP_CTL_EL0		sys_reg(3, 3, 14, 2, 1)
>  #define SYS_CNTP_CVAL_EL0		sys_reg(3, 3, 14, 2, 2)
>  
> +#define SYS_AARCH32_CNTP_TVAL		sys_reg(0, 0, 14, 2, 0)
> +#define SYS_AARCH32_CNTP_CTL		sys_reg(0, 0, 14, 2, 1)
> +#define SYS_AARCH32_CNTP_CVAL		sys_reg(0, 2, 0, 14, 0)
> +
>  #define __PMEV_op2(n)			((n) & 0x7)
>  #define __CNTR_CRm(n)			(0x8 | (((n) >> 3) & 0x3))
>  #define SYS_PMEVCNTRn_EL0(n)		sys_reg(3, 3, 14, __CNTR_CRm(n), __PMEV_op2(n))
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index 1a5bea4285e4..65ea63366c67 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -990,44 +990,51 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>  	{ SYS_DESC(SYS_PMEVTYPERn_EL0(n)),					\
>  	  access_pmu_evtyper, reset_unknown, (PMEVTYPER0_EL0 + n), }
>  
> -static bool access_cntp_tval(struct kvm_vcpu *vcpu,
> -		struct sys_reg_params *p,
> -		const struct sys_reg_desc *r)
> +static bool access_arch_timer(struct kvm_vcpu *vcpu,
> +			      struct sys_reg_params *p,
> +			      const struct sys_reg_desc *r)
>  {
> -	u64 now = kvm_phys_timer_read();
> -	u64 cval;
> +	enum kvm_arch_timers tmr;
> +	enum kvm_arch_timer_regs treg;
> +	u64 reg = reg_to_encoding(r);
>  
> -	if (p->is_write) {
> -		kvm_arm_timer_set_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL,
> -				      p->regval + now);
> -	} else {
> -		cval = kvm_arm_timer_get_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL);
> -		p->regval = cval - now;
> +	switch (reg) {
> +	case SYS_CNTP_TVAL_EL0:
> +	case SYS_CNTP_CTL_EL0:
> +	case SYS_CNTP_CVAL_EL0:
> +	case SYS_AARCH32_CNTP_TVAL:
> +	case SYS_AARCH32_CNTP_CTL:
> +	case SYS_AARCH32_CNTP_CVAL:
> +		tmr = TIMER_PTIMER;
> +		break;
> +	default:
> +		BUG();
>  	}
>  
> -	return true;
> -}
> +	switch (reg) {

I find having two consecutive switch on the same element a bit weird
(and takes a lot of space).

Either I'd merge the two since the valid cases are the same, or I'd put
them in separate function "reg_get_timer(reg)",
"reg_get_timer_reg(reg)". (Can probably fit those in
include/kvm/arm_arch_timer.h)

> +	case SYS_CNTP_CVAL_EL0:
> +	case SYS_AARCH32_CNTP_CVAL:
> +		treg = TIMER_REG_CVAL;
> +		break;
>  
> -static bool access_cntp_ctl(struct kvm_vcpu *vcpu,
> -		struct sys_reg_params *p,
> -		const struct sys_reg_desc *r)
> -{
> -	if (p->is_write)
> -		kvm_arm_timer_set_reg(vcpu, KVM_REG_ARM_PTIMER_CTL, p->regval);
> -	else
> -		p->regval = kvm_arm_timer_get_reg(vcpu, KVM_REG_ARM_PTIMER_CTL);
> +	case SYS_CNTP_TVAL_EL0:
> +	case SYS_AARCH32_CNTP_TVAL:
> +		treg = TIMER_REG_TVAL;
> +		break;
>  
> -	return true;
> -}
> +	case SYS_CNTP_CTL_EL0:
> +	case SYS_AARCH32_CNTP_CTL:
> +		treg = TIMER_REG_CTL;
> +		break;
> +
> +	default:
> +		BUG();
> +	}
>  
> -static bool access_cntp_cval(struct kvm_vcpu *vcpu,
> -		struct sys_reg_params *p,
> -		const struct sys_reg_desc *r)
> -{
>  	if (p->is_write)
> -		kvm_arm_timer_set_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL, p->regval);
> +		kvm_arm_timer_write_sysreg(vcpu, tmr, treg, p->regval);
>  	else
> -		p->regval = kvm_arm_timer_get_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL);
> +		p->regval = kvm_arm_timer_read_sysreg(vcpu, tmr, treg);
>  
>  	return true;
>  }
> @@ -1392,9 +1399,9 @@ static const struct sys_reg_desc sys_reg_descs[] = {
>  	{ SYS_DESC(SYS_TPIDR_EL0), NULL, reset_unknown, TPIDR_EL0 },
>  	{ SYS_DESC(SYS_TPIDRRO_EL0), NULL, reset_unknown, TPIDRRO_EL0 },
>  
> -	{ SYS_DESC(SYS_CNTP_TVAL_EL0), access_cntp_tval },
> -	{ SYS_DESC(SYS_CNTP_CTL_EL0), access_cntp_ctl },
> -	{ SYS_DESC(SYS_CNTP_CVAL_EL0), access_cntp_cval },
> +	{ SYS_DESC(SYS_CNTP_TVAL_EL0), access_arch_timer },
> +	{ SYS_DESC(SYS_CNTP_CTL_EL0), access_arch_timer },
> +	{ SYS_DESC(SYS_CNTP_CVAL_EL0), access_arch_timer },
>  
>  	/* PMEVCNTRn_EL0 */
>  	PMU_PMEVCNTR_EL0(0),
> @@ -1715,10 +1722,9 @@ static const struct sys_reg_desc cp15_regs[] = {
>  
>  	{ Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, c13_CID },
>  
> -	/* CNTP_TVAL */
> -	{ Op1( 0), CRn(14), CRm( 2), Op2( 0), access_cntp_tval },
> -	/* CNTP_CTL */
> -	{ Op1( 0), CRn(14), CRm( 2), Op2( 1), access_cntp_ctl },
> +	/* Arch Tmers */
> +	{ SYS_DESC(SYS_AARCH32_CNTP_TVAL), access_arch_timer },
> +	{ SYS_DESC(SYS_AARCH32_CNTP_CTL), access_arch_timer },
>  
>  	/* PMEVCNTRn */
>  	PMU_PMEVCNTR(0),
> @@ -1795,7 +1801,7 @@ static const struct sys_reg_desc cp15_64_regs[] = {
>  	{ Op1( 1), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, c2_TTBR1 },
>  	{ Op1( 1), CRn( 0), CRm(12), Op2( 0), access_gic_sgi }, /* ICC_ASGI1R */
>  	{ Op1( 2), CRn( 0), CRm(12), Op2( 0), access_gic_sgi }, /* ICC_SGI0R */
> -	{ Op1( 2), CRn( 0), CRm(14), Op2( 0), access_cntp_cval },
> +	{ SYS_DESC(SYS_AARCH32_CNTP_CVAL),    access_arch_timer },
>  };
>  
>  /* Target specific emulation tables */
> diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
> index d6e6a45d1d24..d26b7fde9935 100644
> --- a/include/kvm/arm_arch_timer.h
> +++ b/include/kvm/arm_arch_timer.h
> @@ -22,6 +22,19 @@
>  #include <linux/clocksource.h>
>  #include <linux/hrtimer.h>
>  
> +enum kvm_arch_timers {
> +	TIMER_PTIMER,
> +	TIMER_VTIMER,
> +	NR_KVM_TIMERS
> +};
> +
> +enum kvm_arch_timer_regs {
> +	TIMER_REG_CNT,
> +	TIMER_REG_CVAL,
> +	TIMER_REG_TVAL,
> +	TIMER_REG_CTL,
> +};
> +
>  struct arch_timer_context {
>  	/* Registers: control register, timer value */
>  	u32				cnt_ctl;
> @@ -87,5 +100,15 @@ bool kvm_arch_timer_get_input_level(int vintid);
>  
>  #define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.vtimer)
>  #define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.ptimer)
> +#define vcpu_get_timer(v,t)					\
> +	(t == TIMER_VTIMER ? vcpu_vtimer(v) : vcpu_ptimer(v))
> +
> +u64 kvm_arm_timer_read_sysreg(struct kvm_vcpu *vcpu,
> +			      enum kvm_arch_timers tmr,
> +			      enum kvm_arch_timer_regs treg);
> +void kvm_arm_timer_write_sysreg(struct kvm_vcpu *vcpu,
> +				enum kvm_arch_timers tmr,
> +				enum kvm_arch_timer_regs treg,
> +				u64 val);
> 
>  #endif
> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> index 4986028d9829..9502bb91776b 100644
> --- a/virt/kvm/arm/arch_timer.c
> +++ b/virt/kvm/arm/arch_timer.c
> @@ -25,6 +25,7 @@
>  
>  #include <clocksource/arm_arch_timer.h>
>  #include <asm/arch_timer.h>
> +#include <asm/kvm_emulate.h>
>  #include <asm/kvm_hyp.h>
>  
>  #include <kvm/arm_vgic.h>
> @@ -52,6 +53,13 @@ static bool kvm_timer_irq_can_fire(struct arch_timer_context *timer_ctx);
>  static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
>  				 struct arch_timer_context *timer_ctx);
>  static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx);
> +static void kvm_arm_timer_write(struct kvm_vcpu *vcpu,
> +				struct arch_timer_context *timer,
> +				enum kvm_arch_timer_regs treg,
> +				u64 val);
> +static u64 kvm_arm_timer_read(struct kvm_vcpu *vcpu,
> +			      struct arch_timer_context *timer,
> +			      enum kvm_arch_timer_regs treg);
>  
>  u64 kvm_phys_timer_read(void)
>  {
> @@ -628,24 +636,25 @@ static void kvm_timer_init_interrupt(void *info)
>  
>  int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
>  {
> -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> -	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
> -
>  	switch (regid) {
>  	case KVM_REG_ARM_TIMER_CTL:
> -		vtimer->cnt_ctl = value & ~ARCH_TIMER_CTRL_IT_STAT;
> +		kvm_arm_timer_write(vcpu,
> +				    vcpu_vtimer(vcpu), TIMER_REG_CTL, value);
>  		break;
>  	case KVM_REG_ARM_TIMER_CNT:
>  		update_vtimer_cntvoff(vcpu, kvm_phys_timer_read() - value);
>  		break;
>  	case KVM_REG_ARM_TIMER_CVAL:
> -		vtimer->cnt_cval = value;
> +		kvm_arm_timer_write(vcpu,
> +				    vcpu_vtimer(vcpu), TIMER_REG_CVAL, value);
>  		break;
>  	case KVM_REG_ARM_PTIMER_CTL:
> -		ptimer->cnt_ctl = value & ~ARCH_TIMER_CTRL_IT_STAT;
> +		kvm_arm_timer_write(vcpu,
> +				    vcpu_ptimer(vcpu), TIMER_REG_CTL, value);
>  		break;
>  	case KVM_REG_ARM_PTIMER_CVAL:
> -		ptimer->cnt_cval = value;
> +		kvm_arm_timer_write(vcpu,
> +				    vcpu_ptimer(vcpu), TIMER_REG_CVAL, value);
>  		break;
>  
>  	default:
> @@ -672,26 +681,112 @@ static u64 read_timer_ctl(struct arch_timer_context *timer)
>  
>  u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid)
>  {
> -	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
> -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> -
>  	switch (regid) {
>  	case KVM_REG_ARM_TIMER_CTL:
> -		return read_timer_ctl(vtimer);
> +		return kvm_arm_timer_read(vcpu,
> +					  vcpu_vtimer(vcpu), TIMER_REG_CTL);
>  	case KVM_REG_ARM_TIMER_CNT:
> -		return kvm_phys_timer_read() - vtimer->cntvoff;
> +		return kvm_arm_timer_read(vcpu,
> +					  vcpu_vtimer(vcpu), TIMER_REG_CNT);
>  	case KVM_REG_ARM_TIMER_CVAL:
> -		return vtimer->cnt_cval;
> +		return kvm_arm_timer_read(vcpu,
> +					  vcpu_vtimer(vcpu), TIMER_REG_CVAL);
>  	case KVM_REG_ARM_PTIMER_CTL:
> -		return read_timer_ctl(ptimer);
> -	case KVM_REG_ARM_PTIMER_CVAL:
> -		return ptimer->cnt_cval;
> +		return kvm_arm_timer_read(vcpu,
> +					  vcpu_ptimer(vcpu), TIMER_REG_CTL);
>  	case KVM_REG_ARM_PTIMER_CNT:
> -		return kvm_phys_timer_read();
> +		return kvm_arm_timer_read(vcpu,
> +					  vcpu_vtimer(vcpu), TIMER_REG_CNT);
> +	case KVM_REG_ARM_PTIMER_CVAL:
> +		return kvm_arm_timer_read(vcpu,
> +					  vcpu_ptimer(vcpu), TIMER_REG_CVAL);
>  	}
>  	return (u64)-1;
>  }
>  
> +static u64 kvm_arm_timer_read(struct kvm_vcpu *vcpu,
> +			      struct arch_timer_context *timer,
> +			      enum kvm_arch_timer_regs treg)
> +{
> +	u64 val;
> +
> +	switch (treg) {
> +	case TIMER_REG_TVAL:
> +		val = kvm_phys_timer_read() - timer->cntvoff - timer->cnt_cval;
> +		break;
> +
> +	case TIMER_REG_CTL:
> +		val = read_timer_ctl(timer);
> +		break;
> +
> +	case TIMER_REG_CVAL:
> +		val = timer->cnt_cval;
> +		break;
> +
> +	case TIMER_REG_CNT:
> +		val = kvm_phys_timer_read() - timer->cntvoff;

Unless you really don't want people to read this register, you might
want to add a "break;" here :) .

> +
> +	default:
> +		BUG();
> +	}
> +
> +	return val;
> +}

Cheers,

-- 
Julien Thierry

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 09/14] KVM: arm64: Reuse sys_reg() macro when searching the trap table
  2019-01-24 14:00 ` [PATCH 09/14] KVM: arm64: Reuse sys_reg() macro when searching the trap table Christoffer Dall
@ 2019-01-30  8:57   ` André Przywara
  0 siblings, 0 replies; 33+ messages in thread
From: André Przywara @ 2019-01-30  8:57 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, kvmarm, linux-arm-kernel, kvm

On Thu, 24 Jan 2019 15:00:27 +0100
Christoffer Dall <christoffer.dall@arm.com> wrote:

Hi,

> From: Marc Zyngier <marc.zyngier@arm.com>
> 
> Instead of having an open-coded macro, reuse the sys_reg() macro
> that does the exact same thing.

It's not the exact same thing, is it? It looks like being off by 5 bit
to me. I think the patch is still fine, but maybe mention in the commit
message that this difference is OK since it's only used as a key for
comparing register indices?

Cheers,
Andre.

> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Acked-by: Christoffer Dall <christoffer.dall@arm.com>
> ---
>  arch/arm64/kvm/sys_regs.c | 19 ++++++-------------
>  1 file changed, 6 insertions(+), 13 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index e3e37228ae4e..1a5bea4285e4 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -965,6 +965,10 @@ static bool access_pmuserenr(struct kvm_vcpu
> *vcpu, struct sys_reg_params *p, return true;
>  }
>  
> +#define
> reg_to_encoding(x)						\
> +	sys_reg((u32)(x)->Op0,
> (u32)(x)->Op1,				\
> +		(u32)(x)->CRn, (u32)(x)->CRm, (u32)(x)->Op2);
> +
>  /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in
> one go */ #define
> DBG_BCR_BVR_WCR_WVR_EL1(n)					\
> { SYS_DESC(SYS_DBGBVRn_EL1(n)),
> \ @@ -1820,30 +1824,19 @@ static const struct sys_reg_desc
> *get_target_table(unsigned target, } }
>  
> -#define
> reg_to_match_value(x)						\
> -
> ({								\
> -		unsigned long
> val;					\
> -		val  = (x)->Op0 <<
> 14;					\
> -		val |= (x)->Op1 <<
> 11;					\
> -		val |= (x)->CRn <<
> 7;					\
> -		val |= (x)->CRm <<
> 3;					\
> -		val |=
> (x)->Op2;					\
> -
> val;							\
> -	 })
> -
>  static int match_sys_reg(const void *key, const void *elt)
>  {
>  	const unsigned long pval = (unsigned long)key;
>  	const struct sys_reg_desc *r = elt;
>  
> -	return pval - reg_to_match_value(r);
> +	return pval - reg_to_encoding(r);
>  }
>  
>  static const struct sys_reg_desc *find_reg(const struct
> sys_reg_params *params, const struct sys_reg_desc table[],
>  					 unsigned int num)
>  {
> -	unsigned long pval = reg_to_match_value(params);
> +	unsigned long pval = reg_to_encoding(params);
>  
>  	return bsearch((void *)pval, table, num, sizeof(table[0]),
> match_sys_reg); }


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 10/14] KVM: arm/arm64: consolidate arch timer trap handlers
  2019-01-25 12:33   ` Julien Thierry
@ 2019-01-30 17:38     ` Marc Zyngier
  0 siblings, 0 replies; 33+ messages in thread
From: Marc Zyngier @ 2019-01-30 17:38 UTC (permalink / raw)
  To: Julien Thierry, Christoffer Dall, kvmarm, linux-arm-kernel
  Cc: Andre Przywara, kvm

On 25/01/2019 12:33, Julien Thierry wrote:
> Hi,
> 
> I'm wondering, could this patch be split in two? One for the
> introduction of kvm_arm_timer_read_sysreg() +
> kvm_arm_timer_write_sysreg() and the other for merging the handlers into
> a single function?

Maybe. I'm not sure it brings us much though.

> 
> 
> 
> On 24/01/2019 14:00, Christoffer Dall wrote:
>> From: Andre Przywara <andre.przywara@arm.com>
>>
>> At the moment we have separate system register emulation handlers for
>> each timer register. Actually they are quite similar, and we rely on
>> kvm_arm_timer_[gs]et_reg() for the actual emulation anyways, so let's
>> just merge all of those handlers into one function, which just marshalls
>> the arguments and then hands off to a set of common accessors.
>> This makes extending the emulation to include EL2 timers much easier.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> [Fixed 32-bit VM breakage and reduced to reworking existing code]
>> Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
>> [Fixed 32bit host, general cleanup]
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  arch/arm/kvm/coproc.c           |  23 +++---
>>  arch/arm64/include/asm/sysreg.h |   4 +
>>  arch/arm64/kvm/sys_regs.c       |  80 +++++++++++---------
>>  include/kvm/arm_arch_timer.h    |  23 ++++++
>>  virt/kvm/arm/arch_timer.c       | 129 +++++++++++++++++++++++++++-----
>>  5 files changed, 196 insertions(+), 63 deletions(-)
>>
>> diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
>> index 222c1635bc7a..51863364f8d1 100644
>> --- a/arch/arm/kvm/coproc.c
>> +++ b/arch/arm/kvm/coproc.c
>> @@ -293,15 +293,16 @@ static bool access_cntp_tval(struct kvm_vcpu *vcpu,
>>  			     const struct coproc_params *p,
>>  			     const struct coproc_reg *r)
>>  {
>> -	u64 now = kvm_phys_timer_read();
>> -	u64 val;
>> +	u32 val;
>>  
>>  	if (p->is_write) {
>>  		val = *vcpu_reg(vcpu, p->Rt1);
>> -		kvm_arm_timer_set_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL, val + now);
>> +		kvm_arm_timer_write_sysreg(vcpu,
>> +					   TIMER_PTIMER, TIMER_REG_TVAL, val);
>>  	} else {
>> -		val = kvm_arm_timer_get_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL);
>> -		*vcpu_reg(vcpu, p->Rt1) = val - now;
>> +		val = kvm_arm_timer_read_sysreg(vcpu,
>> +						TIMER_PTIMER, TIMER_REG_TVAL);
>> +		*vcpu_reg(vcpu, p->Rt1) = val;
>>  	}
>>  
>>  	return true;
>> @@ -315,9 +316,11 @@ static bool access_cntp_ctl(struct kvm_vcpu *vcpu,
>>  
>>  	if (p->is_write) {
>>  		val = *vcpu_reg(vcpu, p->Rt1);
>> -		kvm_arm_timer_set_reg(vcpu, KVM_REG_ARM_PTIMER_CTL, val);
>> +		kvm_arm_timer_write_sysreg(vcpu,
>> +					   TIMER_PTIMER, TIMER_REG_CTL, val);
>>  	} else {
>> -		val = kvm_arm_timer_get_reg(vcpu, KVM_REG_ARM_PTIMER_CTL);
>> +		val = kvm_arm_timer_read_sysreg(vcpu,
>> +						TIMER_PTIMER, TIMER_REG_CTL);
>>  		*vcpu_reg(vcpu, p->Rt1) = val;
>>  	}
>>  
>> @@ -333,9 +336,11 @@ static bool access_cntp_cval(struct kvm_vcpu *vcpu,
>>  	if (p->is_write) {
>>  		val = (u64)*vcpu_reg(vcpu, p->Rt2) << 32;
>>  		val |= *vcpu_reg(vcpu, p->Rt1);
>> -		kvm_arm_timer_set_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL, val);
>> +		kvm_arm_timer_write_sysreg(vcpu,
>> +					   TIMER_PTIMER, TIMER_REG_CVAL, val);
>>  	} else {
>> -		val = kvm_arm_timer_get_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL);
>> +		val = kvm_arm_timer_read_sysreg(vcpu,
>> +						TIMER_PTIMER, TIMER_REG_CVAL);
>>  		*vcpu_reg(vcpu, p->Rt1) = val;
>>  		*vcpu_reg(vcpu, p->Rt2) = val >> 32;
>>  	}
>> diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
>> index 3e5650903d6d..6482e8bcf1b8 100644
>> --- a/arch/arm64/include/asm/sysreg.h
>> +++ b/arch/arm64/include/asm/sysreg.h
>> @@ -392,6 +392,10 @@
>>  #define SYS_CNTP_CTL_EL0		sys_reg(3, 3, 14, 2, 1)
>>  #define SYS_CNTP_CVAL_EL0		sys_reg(3, 3, 14, 2, 2)
>>  
>> +#define SYS_AARCH32_CNTP_TVAL		sys_reg(0, 0, 14, 2, 0)
>> +#define SYS_AARCH32_CNTP_CTL		sys_reg(0, 0, 14, 2, 1)
>> +#define SYS_AARCH32_CNTP_CVAL		sys_reg(0, 2, 0, 14, 0)
>> +
>>  #define __PMEV_op2(n)			((n) & 0x7)
>>  #define __CNTR_CRm(n)			(0x8 | (((n) >> 3) & 0x3))
>>  #define SYS_PMEVCNTRn_EL0(n)		sys_reg(3, 3, 14, __CNTR_CRm(n), __PMEV_op2(n))
>> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
>> index 1a5bea4285e4..65ea63366c67 100644
>> --- a/arch/arm64/kvm/sys_regs.c
>> +++ b/arch/arm64/kvm/sys_regs.c
>> @@ -990,44 +990,51 @@ static bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
>>  	{ SYS_DESC(SYS_PMEVTYPERn_EL0(n)),					\
>>  	  access_pmu_evtyper, reset_unknown, (PMEVTYPER0_EL0 + n), }
>>  
>> -static bool access_cntp_tval(struct kvm_vcpu *vcpu,
>> -		struct sys_reg_params *p,
>> -		const struct sys_reg_desc *r)
>> +static bool access_arch_timer(struct kvm_vcpu *vcpu,
>> +			      struct sys_reg_params *p,
>> +			      const struct sys_reg_desc *r)
>>  {
>> -	u64 now = kvm_phys_timer_read();
>> -	u64 cval;
>> +	enum kvm_arch_timers tmr;
>> +	enum kvm_arch_timer_regs treg;
>> +	u64 reg = reg_to_encoding(r);
>>  
>> -	if (p->is_write) {
>> -		kvm_arm_timer_set_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL,
>> -				      p->regval + now);
>> -	} else {
>> -		cval = kvm_arm_timer_get_reg(vcpu, KVM_REG_ARM_PTIMER_CVAL);
>> -		p->regval = cval - now;
>> +	switch (reg) {
>> +	case SYS_CNTP_TVAL_EL0:
>> +	case SYS_CNTP_CTL_EL0:
>> +	case SYS_CNTP_CVAL_EL0:
>> +	case SYS_AARCH32_CNTP_TVAL:
>> +	case SYS_AARCH32_CNTP_CTL:
>> +	case SYS_AARCH32_CNTP_CVAL:
>> +		tmr = TIMER_PTIMER;
>> +		break;
>> +	default:
>> +		BUG();
>>  	}
>>  
>> -	return true;
>> -}
>> +	switch (reg) {
> 
> I find having two consecutive switch on the same element a bit weird
> (and takes a lot of space).
> 
> Either I'd merge the two since the valid cases are the same, or I'd put
> them in separate function "reg_get_timer(reg)",
> "reg_get_timer_reg(reg)". (Can probably fit those in
> include/kvm/arm_arch_timer.h)

Nah, I'll just merge them. I wrote it this way as it was just easier to
reason about one thing at a time, but in the end this is (as you
noticed) fairly pointless.

I guess I'll have more fun rebasing the NV stuff on top! ;-)

[...]

>> +static u64 kvm_arm_timer_read(struct kvm_vcpu *vcpu,
>> +			      struct arch_timer_context *timer,
>> +			      enum kvm_arch_timer_regs treg)
>> +{
>> +	u64 val;
>> +
>> +	switch (treg) {
>> +	case TIMER_REG_TVAL:
>> +		val = kvm_phys_timer_read() - timer->cntvoff - timer->cnt_cval;
>> +		break;
>> +
>> +	case TIMER_REG_CTL:
>> +		val = read_timer_ctl(timer);
>> +		break;
>> +
>> +	case TIMER_REG_CVAL:
>> +		val = timer->cnt_cval;
>> +		break;
>> +
>> +	case TIMER_REG_CNT:
>> +		val = kvm_phys_timer_read() - timer->cntvoff;
> 
> Unless you really don't want people to read this register, you might
> want to add a "break;" here :) .

Timers are for wimps. Real hax0rz use a calibrated loop with interrupts
disabled! ;-)

Thanks for the heads up!

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

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 06/14] KVM: arm/arm64: Factor out VMID into struct kvm_vmid
  2019-01-25 11:05   ` Julien Thierry
@ 2019-01-31 13:01     ` Marc Zyngier
  0 siblings, 0 replies; 33+ messages in thread
From: Marc Zyngier @ 2019-01-31 13:01 UTC (permalink / raw)
  To: Julien Thierry, Christoffer Dall, kvmarm, linux-arm-kernel; +Cc: kvm

On 25/01/2019 11:05, Julien Thierry wrote:
> Hi Christoffer,
> 
> On 24/01/2019 14:00, Christoffer Dall wrote:
>> In preparation for nested virtualization where we are going to have more
>> than a single VMID per VM, let's factor out the VMID data into a
>> separate VMID data structure and change the VMID allocator to operate on
>> this new structure instead of using a struct kvm.
>>
>> This also means that udate_vttbr now becomes update_vmid, and that the
>> vttbr itself is generated on the fly based on the stage 2 page table
>> base address and the vmid.
>>
>> We cache the physical address of the pgd when allocating the pgd to
>> avoid doing the calculation on every entry to the guest and to avoid
>> calling into potentially non-hyp-mapped code from hyp/EL2.
>>
>> If we wanted to merge the VMID allocator with the arm64 ASID allocator
>> at some point in the future, it should actually become easier to do that
>> after this patch.
>>
>> Note that to avoid mapping the kvm_vmid_bits variable into hyp, we
>> simply forego the masking of the vmid value in kvm_get_vttbr and rely on
>> update_vmid to always assign a valid vmid value (within the supported
>> range).
>>
>> Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
>> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  arch/arm/include/asm/kvm_host.h   | 13 ++++---
>>  arch/arm/include/asm/kvm_mmu.h    | 11 ++++++
>>  arch/arm/kvm/hyp/switch.c         |  2 +-
>>  arch/arm/kvm/hyp/tlb.c            |  4 +--
>>  arch/arm64/include/asm/kvm_host.h |  9 +++--
>>  arch/arm64/include/asm/kvm_hyp.h  |  3 +-
>>  arch/arm64/include/asm/kvm_mmu.h  | 11 ++++++
>>  virt/kvm/arm/arm.c                | 57 +++++++++++--------------------
>>  virt/kvm/arm/mmu.c                |  2 ++
>>  9 files changed, 63 insertions(+), 49 deletions(-)
>>
> 
> [...]
> 
>> diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
>> index 3a875fc1b63c..fadbd9ad3a90 100644
>> --- a/arch/arm/include/asm/kvm_mmu.h
>> +++ b/arch/arm/include/asm/kvm_mmu.h
>> @@ -426,6 +426,17 @@ static inline bool kvm_cpu_has_cnp(void)
>>  	return false;
>>  }
>>  
>> +static __always_inline u64 kvm_get_vttbr(struct kvm *kvm)
>> +{
>> +	struct kvm_vmid *vmid = &kvm->arch.vmid;
>> +	u64 vmid_field, baddr;
>> +	u64 cnp = kvm_cpu_has_cnp() ? VTTBR_CNP_BIT : 0;
>> +
> 
> Nit:
> As James pointed out, we're not merging this one with the 64-bit
> version. The question is, since we don't merge it, can't we simplify
> this one by removing the CNP related code from it? (we know CNP is
> always false for 32-bit ARM).

We certainly can.

> 
>> +	baddr = kvm->arch.pgd_phys;
>> +	vmid_field = (u64)vmid->vmid << VTTBR_VMID_SHIFT;
>> +	return kvm_phys_to_vttbr(baddr) | vmid_field | cnp;
>> +}
>> +
>>  #endif	/* !__ASSEMBLY__ */
> 
> Otherwise, things look good to me:
> 
> Reviewed-by: Julien Thierry <julien.thierry@arm.com>

Thanks,

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

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 11/14] KVM: arm/arm64: timer: Rework data structures for multiple timers
  2019-01-24 14:00 ` [PATCH 11/14] KVM: arm/arm64: timer: Rework data structures for multiple timers Christoffer Dall
@ 2019-02-18 15:10   ` André Przywara
  2019-02-19 12:27     ` Christoffer Dall
  0 siblings, 1 reply; 33+ messages in thread
From: André Przywara @ 2019-02-18 15:10 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, kvmarm, linux-arm-kernel, kvm

On Thu, 24 Jan 2019 15:00:29 +0100
Christoffer Dall <christoffer.dall@arm.com> wrote:

Hi,

I already looked at most of these patches earlier, without finding
serious issues, but figured I would give those without any Reviewed-by:
or Acked-by: tags a closer look.
(This patch just carries a S-o-b: tag from Marc in the kvm-arm git repo.)

> Prepare for having 4 timer data structures (2 for now).
> 
> Change loaded to an enum so that we know not just whether *some* state
> is loaded on the CPU, but also *which* state is loaded.
> 
> Move loaded to the cpu data structure and not the individual timer
> structure, in preparation for assigning the EL1 phys timer as well.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  include/kvm/arm_arch_timer.h | 44 ++++++++++++++-------------
>  virt/kvm/arm/arch_timer.c    | 58 +++++++++++++++++++-----------------
>  2 files changed, 54 insertions(+), 48 deletions(-)
> 
> diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
> index d26b7fde9935..d40fe57a2d0d 100644
> --- a/include/kvm/arm_arch_timer.h
> +++ b/include/kvm/arm_arch_timer.h
> @@ -36,6 +36,8 @@ enum kvm_arch_timer_regs {
>  };
>  
>  struct arch_timer_context {
> +	struct kvm_vcpu			*vcpu;
> +
>  	/* Registers: control register, timer value */
>  	u32				cnt_ctl;
>  	u64				cnt_cval;
> @@ -43,32 +45,34 @@ struct arch_timer_context {
>  	/* Timer IRQ */
>  	struct kvm_irq_level		irq;
>  
> -	/*
> -	 * We have multiple paths which can save/restore the timer state
> -	 * onto the hardware, so we need some way of keeping track of
> -	 * where the latest state is.
> -	 *
> -	 * loaded == true:  State is loaded on the hardware registers.
> -	 * loaded == false: State is stored in memory.
> -	 */
> -	bool			loaded;
> -
>  	/* Virtual offset */
> -	u64			cntvoff;
> +	u64				cntvoff;
> +
> +	/* Emulated Timer (may be unused) */
> +	struct hrtimer			hrtimer;
> +};
> +
> +enum loaded_timer_state {
> +	TIMER_NOT_LOADED,
> +	TIMER_EL1_LOADED,

So this gets reverted in PATCH 13/14, and I don't see it reappearing in
the nv series later on.
Is that just needed for assigning the phys timer in the next patch, and
gets obsolete with the timer_map?
Or is this a rebase artefact and we don't actually need this?

The rest of the patch looks like valid transformations to me.

Cheers,
Andre.

>  };
>  
>  struct arch_timer_cpu {
> -	struct arch_timer_context	vtimer;
> -	struct arch_timer_context	ptimer;
> +	struct arch_timer_context timers[NR_KVM_TIMERS];
>  
>  	/* Background timer used when the guest is not running */
>  	struct hrtimer			bg_timer;
>  
> -	/* Physical timer emulation */
> -	struct hrtimer			phys_timer;
> -
>  	/* Is the timer enabled */
>  	bool			enabled;
> +
> +	/*
> +	 * We have multiple paths which can save/restore the timer state
> +	 * onto the hardware, and for nested virt the EL1 hardware timers can
> +	 * contain state from either the VM's EL1 timers or EL2 timers, so we
> +	 * need some way of keeping track of where the latest state is.
> +	 */
> +	enum loaded_timer_state loaded;
>  };
>  
>  int kvm_timer_hyp_init(bool);
> @@ -98,10 +102,10 @@ void kvm_timer_init_vhe(void);
>  
>  bool kvm_arch_timer_get_input_level(int vintid);
>  
> -#define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.vtimer)
> -#define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.ptimer)
> -#define vcpu_get_timer(v,t)					\
> -	(t == TIMER_VTIMER ? vcpu_vtimer(v) : vcpu_ptimer(v))
> +#define vcpu_timer(v)	(&(v)->arch.timer_cpu)
> +#define vcpu_get_timer(v,t)	(&vcpu_timer(v)->timers[(t)])
> +#define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.timers[TIMER_VTIMER])
> +#define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.timers[TIMER_PTIMER])
>  
>  u64 kvm_arm_timer_read_sysreg(struct kvm_vcpu *vcpu,
>  			      enum kvm_arch_timers tmr,
> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> index 9502bb91776b..8b0eca5fbad1 100644
> --- a/virt/kvm/arm/arch_timer.c
> +++ b/virt/kvm/arm/arch_timer.c
> @@ -184,13 +184,11 @@ static enum hrtimer_restart kvm_bg_timer_expire(struct hrtimer *hrt)
>  static enum hrtimer_restart kvm_phys_timer_expire(struct hrtimer *hrt)
>  {
>  	struct arch_timer_context *ptimer;
> -	struct arch_timer_cpu *timer;
>  	struct kvm_vcpu *vcpu;
>  	u64 ns;
>  
> -	timer = container_of(hrt, struct arch_timer_cpu, phys_timer);
> -	vcpu = container_of(timer, struct kvm_vcpu, arch.timer_cpu);
> -	ptimer = vcpu_ptimer(vcpu);
> +	ptimer = container_of(hrt, struct arch_timer_context, hrtimer);
> +	vcpu = ptimer->vcpu;
>  
>  	/*
>  	 * Check that the timer has really expired from the guest's
> @@ -209,9 +207,10 @@ static enum hrtimer_restart kvm_phys_timer_expire(struct hrtimer *hrt)
>  
>  static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx)
>  {
> +	struct arch_timer_cpu *timer = vcpu_timer(timer_ctx->vcpu);
>  	u64 cval, now;
>  
> -	if (timer_ctx->loaded) {
> +	if (timer->loaded == TIMER_EL1_LOADED) {
>  		u32 cnt_ctl;
>  
>  		/* Only the virtual timer can be loaded so far */
> @@ -280,7 +279,6 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
>  /* Schedule the background timer for the emulated timer. */
>  static void phys_timer_emulate(struct kvm_vcpu *vcpu)
>  {
> -	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
>  	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
>  
>  	/*
> @@ -289,11 +287,11 @@ static void phys_timer_emulate(struct kvm_vcpu *vcpu)
>  	 * then we also don't need a soft timer.
>  	 */
>  	if (kvm_timer_should_fire(ptimer) || !kvm_timer_irq_can_fire(ptimer)) {
> -		soft_timer_cancel(&timer->phys_timer);
> +		soft_timer_cancel(&ptimer->hrtimer);
>  		return;
>  	}
>  
> -	soft_timer_start(&timer->phys_timer, kvm_timer_compute_delta(ptimer));
> +	soft_timer_start(&ptimer->hrtimer, kvm_timer_compute_delta(ptimer));
>  }
>  
>  /*
> @@ -303,7 +301,7 @@ static void phys_timer_emulate(struct kvm_vcpu *vcpu)
>   */
>  static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
>  {
> -	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> +	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
>  	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
>  	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
>  	bool level;
> @@ -329,13 +327,13 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
>  
>  static void vtimer_save_state(struct kvm_vcpu *vcpu)
>  {
> -	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> +	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
>  	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
>  	unsigned long flags;
>  
>  	local_irq_save(flags);
>  
> -	if (!vtimer->loaded)
> +	if (timer->loaded == TIMER_NOT_LOADED)
>  		goto out;
>  
>  	if (timer->enabled) {
> @@ -347,7 +345,7 @@ static void vtimer_save_state(struct kvm_vcpu *vcpu)
>  	write_sysreg_el0(0, cntv_ctl);
>  	isb();
>  
> -	vtimer->loaded = false;
> +	timer->loaded = TIMER_NOT_LOADED;
>  out:
>  	local_irq_restore(flags);
>  }
> @@ -359,7 +357,7 @@ static void vtimer_save_state(struct kvm_vcpu *vcpu)
>   */
>  static void kvm_timer_blocking(struct kvm_vcpu *vcpu)
>  {
> -	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> +	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
>  	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
>  	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
>  
> @@ -379,20 +377,20 @@ static void kvm_timer_blocking(struct kvm_vcpu *vcpu)
>  
>  static void kvm_timer_unblocking(struct kvm_vcpu *vcpu)
>  {
> -	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> +	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
>  
>  	soft_timer_cancel(&timer->bg_timer);
>  }
>  
>  static void vtimer_restore_state(struct kvm_vcpu *vcpu)
>  {
> -	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> +	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
>  	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
>  	unsigned long flags;
>  
>  	local_irq_save(flags);
>  
> -	if (vtimer->loaded)
> +	if (timer->loaded == TIMER_EL1_LOADED)
>  		goto out;
>  
>  	if (timer->enabled) {
> @@ -401,7 +399,7 @@ static void vtimer_restore_state(struct kvm_vcpu *vcpu)
>  		write_sysreg_el0(vtimer->cnt_ctl, cntv_ctl);
>  	}
>  
> -	vtimer->loaded = true;
> +	timer->loaded = TIMER_EL1_LOADED;
>  out:
>  	local_irq_restore(flags);
>  }
> @@ -462,7 +460,7 @@ static void kvm_timer_vcpu_load_nogic(struct kvm_vcpu *vcpu)
>  
>  void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
>  {
> -	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> +	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
>  	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
>  	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
>  
> @@ -507,7 +505,8 @@ bool kvm_timer_should_notify_user(struct kvm_vcpu *vcpu)
>  
>  void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
>  {
> -	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> +	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
> +	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
>  
>  	if (unlikely(!timer->enabled))
>  		return;
> @@ -523,7 +522,7 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
>  	 * In any case, we re-schedule the hrtimer for the physical timer when
>  	 * coming back to the VCPU thread in kvm_timer_vcpu_load().
>  	 */
> -	soft_timer_cancel(&timer->phys_timer);
> +	soft_timer_cancel(&ptimer->hrtimer);
>  
>  	if (swait_active(kvm_arch_vcpu_wq(vcpu)))
>  		kvm_timer_blocking(vcpu);
> @@ -559,7 +558,7 @@ static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu)
>  
>  void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
>  {
> -	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> +	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
>  
>  	if (unlikely(!timer->enabled))
>  		return;
> @@ -570,7 +569,7 @@ void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
>  
>  int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu)
>  {
> -	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> +	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
>  	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
>  	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
>  
> @@ -611,22 +610,25 @@ static void update_vtimer_cntvoff(struct kvm_vcpu *vcpu, u64 cntvoff)
>  
>  void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
>  {
> -	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> +	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
>  	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
>  	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
>  
>  	/* Synchronize cntvoff across all vtimers of a VM. */
>  	update_vtimer_cntvoff(vcpu, kvm_phys_timer_read());
> -	vcpu_ptimer(vcpu)->cntvoff = 0;
> +	ptimer->cntvoff = 0;
>  
>  	hrtimer_init(&timer->bg_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
>  	timer->bg_timer.function = kvm_bg_timer_expire;
>  
> -	hrtimer_init(&timer->phys_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
> -	timer->phys_timer.function = kvm_phys_timer_expire;
> +	hrtimer_init(&ptimer->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
> +	ptimer->hrtimer.function = kvm_phys_timer_expire;
>  
>  	vtimer->irq.irq = default_vtimer_irq.irq;
>  	ptimer->irq.irq = default_ptimer_irq.irq;
> +
> +	vtimer->vcpu = vcpu;
> +	ptimer->vcpu = vcpu;
>  }
>  
>  static void kvm_timer_init_interrupt(void *info)
> @@ -859,7 +861,7 @@ int kvm_timer_hyp_init(bool has_gic)
>  
>  void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu)
>  {
> -	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> +	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
>  
>  	soft_timer_cancel(&timer->bg_timer);
>  }
> @@ -903,7 +905,7 @@ bool kvm_arch_timer_get_input_level(int vintid)
>  
>  int kvm_timer_enable(struct kvm_vcpu *vcpu)
>  {
> -	struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
> +	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
>  	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
>  	int ret;
>  


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 12/14] KVM: arm/arm64: arch_timer: Assign the phys timer on VHE systems
  2019-01-24 14:00 ` [PATCH 12/14] KVM: arm/arm64: arch_timer: Assign the phys timer on VHE systems Christoffer Dall
@ 2019-02-18 15:10   ` André Przywara
  2019-02-19 12:43     ` Christoffer Dall
  2019-02-19 11:39   ` Alexandru Elisei
  1 sibling, 1 reply; 33+ messages in thread
From: André Przywara @ 2019-02-18 15:10 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, kvmarm, linux-arm-kernel, kvm

On Thu, 24 Jan 2019 15:00:30 +0100
Christoffer Dall <christoffer.dall@arm.com> wrote:

Hi,

> VHE systems don't have to emulate the physical timer, we can simply
> assigne the EL1 physical timer directly to the VM as the host always
> uses the EL2 timers.
> 
> In order to minimize the amount of cruft, AArch32 gets definitions for
> the physical timer too, but is should be generally unused on this
> architecture.
> 
> Co-written with Marc Zyngier <marc.zyngier@arm.com>
> 
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
> ---
>  arch/arm/include/asm/kvm_hyp.h |   4 +
>  include/kvm/arm_arch_timer.h   |   6 +
>  virt/kvm/arm/arch_timer.c      | 206 ++++++++++++++++++++++++++-------
>  3 files changed, 171 insertions(+), 45 deletions(-)
> 
> diff --git a/arch/arm/include/asm/kvm_hyp.h b/arch/arm/include/asm/kvm_hyp.h
> index e93a0cac9add..87bcd18df8d5 100644
> --- a/arch/arm/include/asm/kvm_hyp.h
> +++ b/arch/arm/include/asm/kvm_hyp.h
> @@ -40,6 +40,7 @@
>  #define TTBR1		__ACCESS_CP15_64(1, c2)
>  #define VTTBR		__ACCESS_CP15_64(6, c2)
>  #define PAR		__ACCESS_CP15_64(0, c7)
> +#define CNTP_CVAL	__ACCESS_CP15_64(2, c14)
>  #define CNTV_CVAL	__ACCESS_CP15_64(3, c14)
>  #define CNTVOFF		__ACCESS_CP15_64(4, c14)
>  
> @@ -85,6 +86,7 @@
>  #define TID_PRIV	__ACCESS_CP15(c13, 0, c0, 4)
>  #define HTPIDR		__ACCESS_CP15(c13, 4, c0, 2)
>  #define CNTKCTL		__ACCESS_CP15(c14, 0, c1, 0)
> +#define CNTP_CTL	__ACCESS_CP15(c14, 0, c2, 1)
>  #define CNTV_CTL	__ACCESS_CP15(c14, 0, c3, 1)
>  #define CNTHCTL		__ACCESS_CP15(c14, 4, c1, 0)
>  
> @@ -94,6 +96,8 @@
>  #define read_sysreg_el0(r)		read_sysreg(r##_el0)
>  #define write_sysreg_el0(v, r)		write_sysreg(v, r##_el0)
>  
> +#define cntp_ctl_el0			CNTP_CTL
> +#define cntp_cval_el0			CNTP_CVAL
>  #define cntv_ctl_el0			CNTV_CTL
>  #define cntv_cval_el0			CNTV_CVAL
>  #define cntvoff_el2			CNTVOFF
> diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
> index d40fe57a2d0d..722e0481f310 100644
> --- a/include/kvm/arm_arch_timer.h
> +++ b/include/kvm/arm_arch_timer.h
> @@ -50,6 +50,10 @@ struct arch_timer_context {
>  
>  	/* Emulated Timer (may be unused) */
>  	struct hrtimer			hrtimer;
> +
> +	/* Duplicated state from arch_timer.c for convenience */
> +	u32				host_timer_irq;
> +	u32				host_timer_irq_flags;
>  };
>  
>  enum loaded_timer_state {
> @@ -107,6 +111,8 @@ bool kvm_arch_timer_get_input_level(int vintid);
>  #define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.timers[TIMER_VTIMER])
>  #define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.timers[TIMER_PTIMER])
>  
> +#define arch_timer_ctx_index(ctx)	((ctx) - vcpu_timer((ctx)->vcpu)->timers)
> +
>  u64 kvm_arm_timer_read_sysreg(struct kvm_vcpu *vcpu,
>  			      enum kvm_arch_timers tmr,
>  			      enum kvm_arch_timer_regs treg);
> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> index 8b0eca5fbad1..eed8f48fbf9b 100644
> --- a/virt/kvm/arm/arch_timer.c
> +++ b/virt/kvm/arm/arch_timer.c
> @@ -35,7 +35,9 @@
>  
>  static struct timecounter *timecounter;
>  static unsigned int host_vtimer_irq;
> +static unsigned int host_ptimer_irq;
>  static u32 host_vtimer_irq_flags;
> +static u32 host_ptimer_irq_flags;
>  
>  static DEFINE_STATIC_KEY_FALSE(has_gic_active_state);
>  
> @@ -86,20 +88,24 @@ static void soft_timer_cancel(struct hrtimer *hrt)
>  static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
>  {
>  	struct kvm_vcpu *vcpu = *(struct kvm_vcpu **)dev_id;
> -	struct arch_timer_context *vtimer;
> +	struct arch_timer_context *ctx;
>  
>  	/*
>  	 * We may see a timer interrupt after vcpu_put() has been called which
>  	 * sets the CPU's vcpu pointer to NULL, because even though the timer
> -	 * has been disabled in vtimer_save_state(), the hardware interrupt
> +	 * has been disabled in timer_save_state(), the hardware interrupt
>  	 * signal may not have been retired from the interrupt controller yet.
>  	 */
>  	if (!vcpu)
>  		return IRQ_HANDLED;
>  
> -	vtimer = vcpu_vtimer(vcpu);
> -	if (kvm_timer_should_fire(vtimer))
> -		kvm_timer_update_irq(vcpu, true, vtimer);
> +	if (irq == host_vtimer_irq)
> +		ctx = vcpu_vtimer(vcpu);
> +	else
> +		ctx = vcpu_ptimer(vcpu);
> +
> +	if (kvm_timer_should_fire(ctx))
> +		kvm_timer_update_irq(vcpu, true, ctx);
>  
>  	if (userspace_irqchip(vcpu->kvm) &&
>  	    !static_branch_unlikely(&has_gic_active_state))
> @@ -208,13 +214,25 @@ static enum hrtimer_restart kvm_phys_timer_expire(struct hrtimer *hrt)
>  static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx)
>  {
>  	struct arch_timer_cpu *timer = vcpu_timer(timer_ctx->vcpu);
> +	enum kvm_arch_timers index = arch_timer_ctx_index(timer_ctx);
>  	u64 cval, now;
>  
>  	if (timer->loaded == TIMER_EL1_LOADED) {
> -		u32 cnt_ctl;
> +		u32 cnt_ctl = 0;
> +
> +		switch (index) {
> +		case TIMER_VTIMER:
> +			cnt_ctl = read_sysreg_el0(cntv_ctl);
> +			break;
> +		case TIMER_PTIMER:
> +			cnt_ctl = read_sysreg_el0(cntp_ctl);
> +			break;
> +		case NR_KVM_TIMERS:
> +			/* GCC is braindead */
> +			cnt_ctl = 0;
> +			break;
> +		}
>  
> -		/* Only the virtual timer can be loaded so far */
> -		cnt_ctl = read_sysreg_el0(cntv_ctl);
>  		return  (cnt_ctl & ARCH_TIMER_CTRL_ENABLE) &&
>  		        (cnt_ctl & ARCH_TIMER_CTRL_IT_STAT) &&
>  		       !(cnt_ctl & ARCH_TIMER_CTRL_IT_MASK);
> @@ -310,7 +328,7 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
>  		return;
>  
>  	/*
> -	 * The vtimer virtual interrupt is a 'mapped' interrupt, meaning part
> +	 * If the timer virtual interrupt is a 'mapped' interrupt, part
>  	 * of its lifecycle is offloaded to the hardware, and we therefore may
>  	 * not have lowered the irq.level value before having to signal a new
>  	 * interrupt, but have to signal an interrupt every time the level is
> @@ -319,31 +337,55 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
>  	level = kvm_timer_should_fire(vtimer);
>  	kvm_timer_update_irq(vcpu, level, vtimer);
>  
> +	if (has_vhe()) {

Not really critical, but wouldn't it be cleaner to use "if
(host_ptimer_irq > 0)" here to check if we map the phys timer as well?
This is at least how we originally derive the decision to initialise
everything in kvm_timer_hyp_init() below. Applies to the other instances
of "if (has_vhe())" as well.
But I guess we use has_vhe() because it's a static key? In this case
would it be worth to define some cosmetic wrapper, to improve readability?

> +		level = kvm_timer_should_fire(ptimer);
> +		kvm_timer_update_irq(vcpu, level, ptimer);
> +
> +		return;
> +	}
> +
>  	phys_timer_emulate(vcpu);
>  
>  	if (kvm_timer_should_fire(ptimer) != ptimer->irq.level)
>  		kvm_timer_update_irq(vcpu, !ptimer->irq.level, ptimer);
>  }
>  
> -static void vtimer_save_state(struct kvm_vcpu *vcpu)
> +static void timer_save_state(struct arch_timer_context *ctx)
>  {
> -	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
> -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> +	struct arch_timer_cpu *timer = vcpu_timer(ctx->vcpu);
> +	enum kvm_arch_timers index = arch_timer_ctx_index(ctx);
>  	unsigned long flags;
>  
> +	if (!timer->enabled)
> +		return;
> +
>  	local_irq_save(flags);
>  
>  	if (timer->loaded == TIMER_NOT_LOADED)
>  		goto out;
>  
> -	if (timer->enabled) {
> -		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> -		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
> -	}
> +	switch (index) {
> +	case TIMER_VTIMER:
> +		ctx->cnt_ctl = read_sysreg_el0(cntv_ctl);
> +		ctx->cnt_cval = read_sysreg_el0(cntv_cval);
>  
> -	/* Disable the virtual timer */
> -	write_sysreg_el0(0, cntv_ctl);
> -	isb();
> +		/* Disable the timer */
> +		write_sysreg_el0(0, cntv_ctl);
> +		isb();
> +
> +		break;
> +	case TIMER_PTIMER:
> +		ctx->cnt_ctl = read_sysreg_el0(cntp_ctl);
> +		ctx->cnt_cval = read_sysreg_el0(cntp_cval);
> +
> +		/* Disable the timer */
> +		write_sysreg_el0(0, cntp_ctl);
> +		isb();
> +
> +		break;
> +	case NR_KVM_TIMERS:
> +		break; /* GCC is braindead */
> +	}
>  
>  	timer->loaded = TIMER_NOT_LOADED;
>  out:
> @@ -382,21 +424,33 @@ static void kvm_timer_unblocking(struct kvm_vcpu *vcpu)
>  	soft_timer_cancel(&timer->bg_timer);
>  }
>  
> -static void vtimer_restore_state(struct kvm_vcpu *vcpu)
> +static void timer_restore_state(struct arch_timer_context *ctx)
>  {
> -	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
> -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> +	struct arch_timer_cpu *timer = vcpu_timer(ctx->vcpu);
> +	enum kvm_arch_timers index = arch_timer_ctx_index(ctx);
>  	unsigned long flags;
>  
> +	if (!timer->enabled)
> +		return;
> +
>  	local_irq_save(flags);
>  
>  	if (timer->loaded == TIMER_EL1_LOADED)
>  		goto out;
>  
> -	if (timer->enabled) {
> -		write_sysreg_el0(vtimer->cnt_cval, cntv_cval);
> +	switch (index) {
> +	case TIMER_VTIMER:
> +		write_sysreg_el0(ctx->cnt_cval, cntv_cval);
> +		isb();
> +		write_sysreg_el0(ctx->cnt_ctl, cntv_ctl);
> +		break;
> +	case TIMER_PTIMER:
> +		write_sysreg_el0(ctx->cnt_cval, cntp_cval);
>  		isb();
> -		write_sysreg_el0(vtimer->cnt_ctl, cntv_ctl);
> +		write_sysreg_el0(ctx->cnt_ctl, cntp_ctl);
> +		break;
> +	case NR_KVM_TIMERS:
> +		break; /* GCC is braindead */
>  	}
>  
>  	timer->loaded = TIMER_EL1_LOADED;
> @@ -419,23 +473,23 @@ static void set_cntvoff(u64 cntvoff)
>  	kvm_call_hyp(__kvm_timer_set_cntvoff, low, high);
>  }
>  
> -static inline void set_vtimer_irq_phys_active(struct kvm_vcpu *vcpu, bool active)
> +static inline void set_timer_irq_phys_active(struct arch_timer_context *ctx, bool active)
>  {
>  	int r;
> -	r = irq_set_irqchip_state(host_vtimer_irq, IRQCHIP_STATE_ACTIVE, active);
> +	r = irq_set_irqchip_state(ctx->host_timer_irq, IRQCHIP_STATE_ACTIVE, active);
>  	WARN_ON(r);
>  }
>  
> -static void kvm_timer_vcpu_load_gic(struct kvm_vcpu *vcpu)
> +static void kvm_timer_vcpu_load_gic(struct arch_timer_context *ctx)
>  {
> -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> +	struct kvm_vcpu *vcpu = ctx->vcpu;
>  	bool phys_active;
>  
>  	if (irqchip_in_kernel(vcpu->kvm))
> -		phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
> +		phys_active = kvm_vgic_map_is_active(vcpu, ctx->irq.irq);
>  	else
> -		phys_active = vtimer->irq.level;
> -	set_vtimer_irq_phys_active(vcpu, phys_active);
> +		phys_active = ctx->irq.level;
> +	set_timer_irq_phys_active(ctx, phys_active);
>  }
>  
>  static void kvm_timer_vcpu_load_nogic(struct kvm_vcpu *vcpu)
> @@ -467,14 +521,22 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
>  	if (unlikely(!timer->enabled))
>  		return;
>  
> -	if (static_branch_likely(&has_gic_active_state))
> -		kvm_timer_vcpu_load_gic(vcpu);
> -	else
> +	if (static_branch_likely(&has_gic_active_state)) {
> +		kvm_timer_vcpu_load_gic(vtimer);
> +		if (has_vhe())
> +			kvm_timer_vcpu_load_gic(ptimer);
> +	} else {
>  		kvm_timer_vcpu_load_nogic(vcpu);
> +	}
>  
>  	set_cntvoff(vtimer->cntvoff);
>  
> -	vtimer_restore_state(vcpu);
> +	timer_restore_state(vtimer);
> +
> +	if (has_vhe()) {
> +		timer_restore_state(ptimer);
> +		return;
> +	}
>  
>  	/* Set the background timer for the physical timer emulation. */
>  	phys_timer_emulate(vcpu);
> @@ -506,12 +568,17 @@ bool kvm_timer_should_notify_user(struct kvm_vcpu *vcpu)
>  void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
>  {
>  	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
> +	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
>  	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
>  
>  	if (unlikely(!timer->enabled))
>  		return;
>  
> -	vtimer_save_state(vcpu);
> +	timer_save_state(vtimer);
> +	if (has_vhe()) {
> +		timer_save_state(ptimer);
> +		return;
> +	}
>  
>  	/*
>  	 * Cancel the physical timer emulation, because the only case where we
> @@ -534,8 +601,7 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
>  	 * counter of non-VHE case. For VHE, the virtual counter uses a fixed
>  	 * virtual offset of zero, so no need to zero CNTVOFF_EL2 register.
>  	 */
> -	if (!has_vhe())
> -		set_cntvoff(0);
> +	set_cntvoff(0);
>  }
>  
>  /*
> @@ -550,7 +616,7 @@ static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu)
>  	if (!kvm_timer_should_fire(vtimer)) {
>  		kvm_timer_update_irq(vcpu, false, vtimer);
>  		if (static_branch_likely(&has_gic_active_state))
> -			set_vtimer_irq_phys_active(vcpu, false);
> +			set_timer_irq_phys_active(vtimer, false);
>  		else
>  			enable_percpu_irq(host_vtimer_irq, host_vtimer_irq_flags);
>  	}
> @@ -625,7 +691,12 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
>  	ptimer->hrtimer.function = kvm_phys_timer_expire;
>  
>  	vtimer->irq.irq = default_vtimer_irq.irq;
> +	vtimer->host_timer_irq = host_vtimer_irq;
> +	vtimer->host_timer_irq_flags = host_vtimer_irq_flags;
> +
>  	ptimer->irq.irq = default_ptimer_irq.irq;
> +	ptimer->host_timer_irq = host_ptimer_irq;
> +	ptimer->host_timer_irq_flags = host_ptimer_irq_flags;
>  
>  	vtimer->vcpu = vcpu;
>  	ptimer->vcpu = vcpu;
> @@ -634,6 +705,7 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
>  static void kvm_timer_init_interrupt(void *info)
>  {
>  	enable_percpu_irq(host_vtimer_irq, host_vtimer_irq_flags);
> +	enable_percpu_irq(host_ptimer_irq, host_ptimer_irq_flags);

Shouldn't we only enable host_ptimer_irq() if we actually pass this on
here? So either guarded by has_vhe() or (host_ptimer_irq > 0)?
Otherwise we would enable IRQ 0?


The rest of the code looks like being a valid extension from "pass on
the vtimer only" to "pass on the ptimer as well if we are using VHE".

Cheers,
Andre.


>  }
>  
>  int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
> @@ -814,6 +886,8 @@ int kvm_timer_hyp_init(bool has_gic)
>  		return -ENODEV;
>  	}
>  
> +	/* First, do the virtual EL1 timer irq */
> +
>  	if (info->virtual_irq <= 0) {
>  		kvm_err("kvm_arch_timer: invalid virtual timer IRQ: %d\n",
>  			info->virtual_irq);
> @@ -824,15 +898,15 @@ int kvm_timer_hyp_init(bool has_gic)
>  	host_vtimer_irq_flags = irq_get_trigger_type(host_vtimer_irq);
>  	if (host_vtimer_irq_flags != IRQF_TRIGGER_HIGH &&
>  	    host_vtimer_irq_flags != IRQF_TRIGGER_LOW) {
> -		kvm_err("Invalid trigger for IRQ%d, assuming level low\n",
> +		kvm_err("Invalid trigger for vtimer IRQ%d, assuming level low\n",
>  			host_vtimer_irq);
>  		host_vtimer_irq_flags = IRQF_TRIGGER_LOW;
>  	}
>  
>  	err = request_percpu_irq(host_vtimer_irq, kvm_arch_timer_handler,
> -				 "kvm guest timer", kvm_get_running_vcpus());
> +				 "kvm guest vtimer", kvm_get_running_vcpus());
>  	if (err) {
> -		kvm_err("kvm_arch_timer: can't request interrupt %d (%d)\n",
> +		kvm_err("kvm_arch_timer: can't request vtimer interrupt %d (%d)\n",
>  			host_vtimer_irq, err);
>  		return err;
>  	}
> @@ -850,6 +924,38 @@ int kvm_timer_hyp_init(bool has_gic)
>  
>  	kvm_debug("virtual timer IRQ%d\n", host_vtimer_irq);
>  
> +	/* Now let's do the physical EL1 timer irq */
> +
> +	if (info->physical_irq > 0) {
> +		host_ptimer_irq = info->physical_irq;
> +		host_ptimer_irq_flags = irq_get_trigger_type(host_ptimer_irq);
> +		if (host_ptimer_irq_flags != IRQF_TRIGGER_HIGH &&
> +		    host_ptimer_irq_flags != IRQF_TRIGGER_LOW) {
> +			kvm_err("Invalid trigger for ptimer IRQ%d, assuming level low\n",
> +				host_ptimer_irq);
> +			host_ptimer_irq_flags = IRQF_TRIGGER_LOW;
> +		}
> +
> +		err = request_percpu_irq(host_ptimer_irq, kvm_arch_timer_handler,
> +					 "kvm guest ptimer", kvm_get_running_vcpus());
> +		if (err) {
> +			kvm_err("kvm_arch_timer: can't request ptimer interrupt %d (%d)\n",
> +				host_ptimer_irq, err);
> +			return err;
> +		}
> +
> +		if (has_gic) {
> +			err = irq_set_vcpu_affinity(host_ptimer_irq,
> +						    kvm_get_running_vcpus());
> +			if (err) {
> +				kvm_err("kvm_arch_timer: error setting vcpu affinity\n");
> +				goto out_free_irq;
> +			}
> +		}
> +
> +		kvm_debug("physical timer IRQ%d\n", host_ptimer_irq);
> +	}
> +
>  	cpuhp_setup_state(CPUHP_AP_KVM_ARM_TIMER_STARTING,
>  			  "kvm/arm/timer:starting", kvm_timer_starting_cpu,
>  			  kvm_timer_dying_cpu);
> @@ -897,8 +1003,10 @@ bool kvm_arch_timer_get_input_level(int vintid)
>  
>  	if (vintid == vcpu_vtimer(vcpu)->irq.irq)
>  		timer = vcpu_vtimer(vcpu);
> +	else if (vintid == vcpu_ptimer(vcpu)->irq.irq)
> +		timer = vcpu_ptimer(vcpu);
>  	else
> -		BUG(); /* We only map the vtimer so far */
> +		BUG();
>  
>  	return kvm_timer_should_fire(timer);
>  }
> @@ -907,6 +1015,7 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
>  {
>  	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
>  	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> +	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
>  	int ret;
>  
>  	if (timer->enabled)
> @@ -929,6 +1038,13 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
>  	if (ret)
>  		return ret;
>  
> +	if (has_vhe()) {
> +		ret = kvm_vgic_map_phys_irq(vcpu, host_ptimer_irq, ptimer->irq.irq,
> +					    kvm_arch_timer_get_input_level);
> +		if (ret)
> +			return ret;
> +	}
> +
>  no_vgic:
>  	timer->enabled = 1;
>  	return 0;
> @@ -951,7 +1067,7 @@ void kvm_timer_init_vhe(void)
>  	 * Physical counter access is allowed.
>  	 */
>  	val = read_sysreg(cnthctl_el2);
> -	val &= ~(CNTHCTL_EL1PCEN << cnthctl_shift);
> +	val |= (CNTHCTL_EL1PCEN << cnthctl_shift);
>  	val |= (CNTHCTL_EL1PCTEN << cnthctl_shift);
>  	write_sysreg(val, cnthctl_el2);
>  }


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 12/14] KVM: arm/arm64: arch_timer: Assign the phys timer on VHE systems
  2019-01-24 14:00 ` [PATCH 12/14] KVM: arm/arm64: arch_timer: Assign the phys timer on VHE systems Christoffer Dall
  2019-02-18 15:10   ` André Przywara
@ 2019-02-19 11:39   ` Alexandru Elisei
  2019-02-19 13:03     ` Christoffer Dall
  1 sibling, 1 reply; 33+ messages in thread
From: Alexandru Elisei @ 2019-02-19 11:39 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, kvm


On 1/24/19 2:00 PM, Christoffer Dall wrote:
> VHE systems don't have to emulate the physical timer, we can simply
> assigne the EL1 physical timer directly to the VM as the host always
> uses the EL2 timers.
>
> In order to minimize the amount of cruft, AArch32 gets definitions for
> the physical timer too, but is should be generally unused on this
> architecture.
>
> Co-written with Marc Zyngier <marc.zyngier@arm.com>
>
> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
> ---
>  arch/arm/include/asm/kvm_hyp.h |   4 +
>  include/kvm/arm_arch_timer.h   |   6 +
>  virt/kvm/arm/arch_timer.c      | 206 ++++++++++++++++++++++++++-------
>  3 files changed, 171 insertions(+), 45 deletions(-)
>
> diff --git a/arch/arm/include/asm/kvm_hyp.h b/arch/arm/include/asm/kvm_hyp.h
> index e93a0cac9add..87bcd18df8d5 100644
> --- a/arch/arm/include/asm/kvm_hyp.h
> +++ b/arch/arm/include/asm/kvm_hyp.h
> @@ -40,6 +40,7 @@
>  #define TTBR1		__ACCESS_CP15_64(1, c2)
>  #define VTTBR		__ACCESS_CP15_64(6, c2)
>  #define PAR		__ACCESS_CP15_64(0, c7)
> +#define CNTP_CVAL	__ACCESS_CP15_64(2, c14)
>  #define CNTV_CVAL	__ACCESS_CP15_64(3, c14)
>  #define CNTVOFF		__ACCESS_CP15_64(4, c14)
>  
> @@ -85,6 +86,7 @@
>  #define TID_PRIV	__ACCESS_CP15(c13, 0, c0, 4)
>  #define HTPIDR		__ACCESS_CP15(c13, 4, c0, 2)
>  #define CNTKCTL		__ACCESS_CP15(c14, 0, c1, 0)
> +#define CNTP_CTL	__ACCESS_CP15(c14, 0, c2, 1)
>  #define CNTV_CTL	__ACCESS_CP15(c14, 0, c3, 1)
>  #define CNTHCTL		__ACCESS_CP15(c14, 4, c1, 0)
>  
> @@ -94,6 +96,8 @@
>  #define read_sysreg_el0(r)		read_sysreg(r##_el0)
>  #define write_sysreg_el0(v, r)		write_sysreg(v, r##_el0)
>  
> +#define cntp_ctl_el0			CNTP_CTL
> +#define cntp_cval_el0			CNTP_CVAL
>  #define cntv_ctl_el0			CNTV_CTL
>  #define cntv_cval_el0			CNTV_CVAL
>  #define cntvoff_el2			CNTVOFF
> diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
> index d40fe57a2d0d..722e0481f310 100644
> --- a/include/kvm/arm_arch_timer.h
> +++ b/include/kvm/arm_arch_timer.h
> @@ -50,6 +50,10 @@ struct arch_timer_context {
>  
>  	/* Emulated Timer (may be unused) */
>  	struct hrtimer			hrtimer;
> +
> +	/* Duplicated state from arch_timer.c for convenience */
> +	u32				host_timer_irq;
> +	u32				host_timer_irq_flags;
>  };
>  
>  enum loaded_timer_state {
> @@ -107,6 +111,8 @@ bool kvm_arch_timer_get_input_level(int vintid);
>  #define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.timers[TIMER_VTIMER])
>  #define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.timers[TIMER_PTIMER])
>  
> +#define arch_timer_ctx_index(ctx)	((ctx) - vcpu_timer((ctx)->vcpu)->timers)
> +
>  u64 kvm_arm_timer_read_sysreg(struct kvm_vcpu *vcpu,
>  			      enum kvm_arch_timers tmr,
>  			      enum kvm_arch_timer_regs treg);
> diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> index 8b0eca5fbad1..eed8f48fbf9b 100644
> --- a/virt/kvm/arm/arch_timer.c
> +++ b/virt/kvm/arm/arch_timer.c
> @@ -35,7 +35,9 @@
>  
>  static struct timecounter *timecounter;
>  static unsigned int host_vtimer_irq;
> +static unsigned int host_ptimer_irq;
>  static u32 host_vtimer_irq_flags;
> +static u32 host_ptimer_irq_flags;
>  
>  static DEFINE_STATIC_KEY_FALSE(has_gic_active_state);
>  
> @@ -86,20 +88,24 @@ static void soft_timer_cancel(struct hrtimer *hrt)
>  static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
>  {
>  	struct kvm_vcpu *vcpu = *(struct kvm_vcpu **)dev_id;
> -	struct arch_timer_context *vtimer;
> +	struct arch_timer_context *ctx;
>  
>  	/*
>  	 * We may see a timer interrupt after vcpu_put() has been called which
>  	 * sets the CPU's vcpu pointer to NULL, because even though the timer
> -	 * has been disabled in vtimer_save_state(), the hardware interrupt
> +	 * has been disabled in timer_save_state(), the hardware interrupt
>  	 * signal may not have been retired from the interrupt controller yet.
>  	 */
>  	if (!vcpu)
>  		return IRQ_HANDLED;
>  
> -	vtimer = vcpu_vtimer(vcpu);
> -	if (kvm_timer_should_fire(vtimer))
> -		kvm_timer_update_irq(vcpu, true, vtimer);
> +	if (irq == host_vtimer_irq)
> +		ctx = vcpu_vtimer(vcpu);
> +	else
> +		ctx = vcpu_ptimer(vcpu);
> +
> +	if (kvm_timer_should_fire(ctx))
> +		kvm_timer_update_irq(vcpu, true, ctx);
>  
>  	if (userspace_irqchip(vcpu->kvm) &&
>  	    !static_branch_unlikely(&has_gic_active_state))
> @@ -208,13 +214,25 @@ static enum hrtimer_restart kvm_phys_timer_expire(struct hrtimer *hrt)
>  static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx)
>  {
>  	struct arch_timer_cpu *timer = vcpu_timer(timer_ctx->vcpu);
> +	enum kvm_arch_timers index = arch_timer_ctx_index(timer_ctx);
>  	u64 cval, now;
>  
>  	if (timer->loaded == TIMER_EL1_LOADED) {
> -		u32 cnt_ctl;
> +		u32 cnt_ctl = 0;
> +
> +		switch (index) {
> +		case TIMER_VTIMER:
> +			cnt_ctl = read_sysreg_el0(cntv_ctl);
> +			break;
> +		case TIMER_PTIMER:
> +			cnt_ctl = read_sysreg_el0(cntp_ctl);
> +			break;
> +		case NR_KVM_TIMERS:
> +			/* GCC is braindead */
> +			cnt_ctl = 0;
> +			break;
> +		}
>  
> -		/* Only the virtual timer can be loaded so far */
> -		cnt_ctl = read_sysreg_el0(cntv_ctl);
>  		return  (cnt_ctl & ARCH_TIMER_CTRL_ENABLE) &&
>  		        (cnt_ctl & ARCH_TIMER_CTRL_IT_STAT) &&
>  		       !(cnt_ctl & ARCH_TIMER_CTRL_IT_MASK);
> @@ -310,7 +328,7 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
>  		return;
>  
>  	/*
> -	 * The vtimer virtual interrupt is a 'mapped' interrupt, meaning part
> +	 * If the timer virtual interrupt is a 'mapped' interrupt, part
>  	 * of its lifecycle is offloaded to the hardware, and we therefore may
>  	 * not have lowered the irq.level value before having to signal a new
>  	 * interrupt, but have to signal an interrupt every time the level is
> @@ -319,31 +337,55 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
>  	level = kvm_timer_should_fire(vtimer);
>  	kvm_timer_update_irq(vcpu, level, vtimer);
>  
> +	if (has_vhe()) {
> +		level = kvm_timer_should_fire(ptimer);
> +		kvm_timer_update_irq(vcpu, level, ptimer);
> +
> +		return;
> +	}
> +
>  	phys_timer_emulate(vcpu);
>  
>  	if (kvm_timer_should_fire(ptimer) != ptimer->irq.level)
>  		kvm_timer_update_irq(vcpu, !ptimer->irq.level, ptimer);
>  }
>  
> -static void vtimer_save_state(struct kvm_vcpu *vcpu)
> +static void timer_save_state(struct arch_timer_context *ctx)
>  {
> -	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
> -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> +	struct arch_timer_cpu *timer = vcpu_timer(ctx->vcpu);
> +	enum kvm_arch_timers index = arch_timer_ctx_index(ctx);
>  	unsigned long flags;
>  
> +	if (!timer->enabled)
> +		return;
> +
>  	local_irq_save(flags);
>  
>  	if (timer->loaded == TIMER_NOT_LOADED)
>  		goto out;
>  
> -	if (timer->enabled) {
> -		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> -		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
> -	}
> +	switch (index) {
> +	case TIMER_VTIMER:
> +		ctx->cnt_ctl = read_sysreg_el0(cntv_ctl);
> +		ctx->cnt_cval = read_sysreg_el0(cntv_cval);
>  
> -	/* Disable the virtual timer */
> -	write_sysreg_el0(0, cntv_ctl);
> -	isb();
> +		/* Disable the timer */
> +		write_sysreg_el0(0, cntv_ctl);
> +		isb();
> +
> +		break;
> +	case TIMER_PTIMER:
> +		ctx->cnt_ctl = read_sysreg_el0(cntp_ctl);
> +		ctx->cnt_cval = read_sysreg_el0(cntp_cval);
> +
> +		/* Disable the timer */
> +		write_sysreg_el0(0, cntp_ctl);
> +		isb();
> +
> +		break;
> +	case NR_KVM_TIMERS:
> +		break; /* GCC is braindead */
> +	}
>  
>  	timer->loaded = TIMER_NOT_LOADED;
>  out:
> @@ -382,21 +424,33 @@ static void kvm_timer_unblocking(struct kvm_vcpu *vcpu)
>  	soft_timer_cancel(&timer->bg_timer);
>  }
>  
> -static void vtimer_restore_state(struct kvm_vcpu *vcpu)
> +static void timer_restore_state(struct arch_timer_context *ctx)
>  {
> -	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
> -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> +	struct arch_timer_cpu *timer = vcpu_timer(ctx->vcpu);
> +	enum kvm_arch_timers index = arch_timer_ctx_index(ctx);
>  	unsigned long flags;
>  
> +	if (!timer->enabled)
> +		return;
> +
>  	local_irq_save(flags);
>  
>  	if (timer->loaded == TIMER_EL1_LOADED)
>  		goto out;
>  
> -	if (timer->enabled) {
> -		write_sysreg_el0(vtimer->cnt_cval, cntv_cval);
> +	switch (index) {
> +	case TIMER_VTIMER:
> +		write_sysreg_el0(ctx->cnt_cval, cntv_cval);
> +		isb();
> +		write_sysreg_el0(ctx->cnt_ctl, cntv_ctl);
> +		break;
> +	case TIMER_PTIMER:
> +		write_sysreg_el0(ctx->cnt_cval, cntp_cval);
>  		isb();
> -		write_sysreg_el0(vtimer->cnt_ctl, cntv_ctl);
> +		write_sysreg_el0(ctx->cnt_ctl, cntp_ctl);
> +		break;
> +	case NR_KVM_TIMERS:
> +		break; /* GCC is braindead */
>  	}
>  
>  	timer->loaded = TIMER_EL1_LOADED;
> @@ -419,23 +473,23 @@ static void set_cntvoff(u64 cntvoff)
>  	kvm_call_hyp(__kvm_timer_set_cntvoff, low, high);
>  }
>  
> -static inline void set_vtimer_irq_phys_active(struct kvm_vcpu *vcpu, bool active)
> +static inline void set_timer_irq_phys_active(struct arch_timer_context *ctx, bool active)
>  {
>  	int r;
> -	r = irq_set_irqchip_state(host_vtimer_irq, IRQCHIP_STATE_ACTIVE, active);
> +	r = irq_set_irqchip_state(ctx->host_timer_irq, IRQCHIP_STATE_ACTIVE, active);
>  	WARN_ON(r);
>  }
>  
> -static void kvm_timer_vcpu_load_gic(struct kvm_vcpu *vcpu)
> +static void kvm_timer_vcpu_load_gic(struct arch_timer_context *ctx)
>  {
> -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> +	struct kvm_vcpu *vcpu = ctx->vcpu;
>  	bool phys_active;
>  
>  	if (irqchip_in_kernel(vcpu->kvm))
> -		phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
> +		phys_active = kvm_vgic_map_is_active(vcpu, ctx->irq.irq);
>  	else
> -		phys_active = vtimer->irq.level;
> -	set_vtimer_irq_phys_active(vcpu, phys_active);
> +		phys_active = ctx->irq.level;
> +	set_timer_irq_phys_active(ctx, phys_active);
>  }
>  
>  static void kvm_timer_vcpu_load_nogic(struct kvm_vcpu *vcpu)
> @@ -467,14 +521,22 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
>  	if (unlikely(!timer->enabled))
>  		return;
>  
> -	if (static_branch_likely(&has_gic_active_state))
> -		kvm_timer_vcpu_load_gic(vcpu);
> -	else
> +	if (static_branch_likely(&has_gic_active_state)) {
> +		kvm_timer_vcpu_load_gic(vtimer);
> +		if (has_vhe())
> +			kvm_timer_vcpu_load_gic(ptimer);
> +	} else {
>  		kvm_timer_vcpu_load_nogic(vcpu);
> +	}
>  
>  	set_cntvoff(vtimer->cntvoff);
>  
> -	vtimer_restore_state(vcpu);
> +	timer_restore_state(vtimer);
> +
> +	if (has_vhe()) {
> +		timer_restore_state(ptimer);
> +		return;
> +	}
>  
>  	/* Set the background timer for the physical timer emulation. */
>  	phys_timer_emulate(vcpu);
> @@ -506,12 +568,17 @@ bool kvm_timer_should_notify_user(struct kvm_vcpu *vcpu)
>  void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
>  {
>  	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
> +	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
>  	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
>  
>  	if (unlikely(!timer->enabled))
>  		return;
>  
> -	vtimer_save_state(vcpu);
> +	timer_save_state(vtimer);
> +	if (has_vhe()) {
> +		timer_save_state(ptimer);
> +		return;
> +	}
>  
>  	/*
>  	 * Cancel the physical timer emulation, because the only case where we
> @@ -534,8 +601,7 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
>  	 * counter of non-VHE case. For VHE, the virtual counter uses a fixed
>  	 * virtual offset of zero, so no need to zero CNTVOFF_EL2 register.
>  	 */
> -	if (!has_vhe())
> -		set_cntvoff(0);
> +	set_cntvoff(0);
>  }
>  
>  /*
> @@ -550,7 +616,7 @@ static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu)
>  	if (!kvm_timer_should_fire(vtimer)) {
>  		kvm_timer_update_irq(vcpu, false, vtimer);
>  		if (static_branch_likely(&has_gic_active_state))
> -			set_vtimer_irq_phys_active(vcpu, false);
> +			set_timer_irq_phys_active(vtimer, false);
>  		else
>  			enable_percpu_irq(host_vtimer_irq, host_vtimer_irq_flags);
>  	}
> @@ -625,7 +691,12 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
>  	ptimer->hrtimer.function = kvm_phys_timer_expire;
>  
>  	vtimer->irq.irq = default_vtimer_irq.irq;
> +	vtimer->host_timer_irq = host_vtimer_irq;
> +	vtimer->host_timer_irq_flags = host_vtimer_irq_flags;
> +
>  	ptimer->irq.irq = default_ptimer_irq.irq;
> +	ptimer->host_timer_irq = host_ptimer_irq;
> +	ptimer->host_timer_irq_flags = host_ptimer_irq_flags;
>  
>  	vtimer->vcpu = vcpu;
>  	ptimer->vcpu = vcpu;
> @@ -634,6 +705,7 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
>  static void kvm_timer_init_interrupt(void *info)
>  {
>  	enable_percpu_irq(host_vtimer_irq, host_vtimer_irq_flags);
> +	enable_percpu_irq(host_ptimer_irq, host_ptimer_irq_flags);
>  }
>  
>  int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
> @@ -814,6 +886,8 @@ int kvm_timer_hyp_init(bool has_gic)
>  		return -ENODEV;
>  	}
>  
> +	/* First, do the virtual EL1 timer irq */
> +
>  	if (info->virtual_irq <= 0) {
>  		kvm_err("kvm_arch_timer: invalid virtual timer IRQ: %d\n",
>  			info->virtual_irq);
> @@ -824,15 +898,15 @@ int kvm_timer_hyp_init(bool has_gic)
>  	host_vtimer_irq_flags = irq_get_trigger_type(host_vtimer_irq);
>  	if (host_vtimer_irq_flags != IRQF_TRIGGER_HIGH &&
>  	    host_vtimer_irq_flags != IRQF_TRIGGER_LOW) {
> -		kvm_err("Invalid trigger for IRQ%d, assuming level low\n",
> +		kvm_err("Invalid trigger for vtimer IRQ%d, assuming level low\n",
>  			host_vtimer_irq);
>  		host_vtimer_irq_flags = IRQF_TRIGGER_LOW;
>  	}
>  
>  	err = request_percpu_irq(host_vtimer_irq, kvm_arch_timer_handler,
> -				 "kvm guest timer", kvm_get_running_vcpus());
> +				 "kvm guest vtimer", kvm_get_running_vcpus());
>  	if (err) {
> -		kvm_err("kvm_arch_timer: can't request interrupt %d (%d)\n",
> +		kvm_err("kvm_arch_timer: can't request vtimer interrupt %d (%d)\n",
>  			host_vtimer_irq, err);
>  		return err;
>  	}
> @@ -850,6 +924,38 @@ int kvm_timer_hyp_init(bool has_gic)
>  
>  	kvm_debug("virtual timer IRQ%d\n", host_vtimer_irq);
>  
> +	/* Now let's do the physical EL1 timer irq */
> +
> +	if (info->physical_irq > 0) {
> +		host_ptimer_irq = info->physical_irq;
> +		host_ptimer_irq_flags = irq_get_trigger_type(host_ptimer_irq);
> +		if (host_ptimer_irq_flags != IRQF_TRIGGER_HIGH &&
> +		    host_ptimer_irq_flags != IRQF_TRIGGER_LOW) {
> +			kvm_err("Invalid trigger for ptimer IRQ%d, assuming level low\n",
> +				host_ptimer_irq);
> +			host_ptimer_irq_flags = IRQF_TRIGGER_LOW;
> +		}
> +
> +		err = request_percpu_irq(host_ptimer_irq, kvm_arch_timer_handler,
> +					 "kvm guest ptimer", kvm_get_running_vcpus());
> +		if (err) {
> +			kvm_err("kvm_arch_timer: can't request ptimer interrupt %d (%d)\n",
> +				host_ptimer_irq, err);
> +			return err;
> +		}
> +
> +		if (has_gic) {
> +			err = irq_set_vcpu_affinity(host_ptimer_irq,
> +						    kvm_get_running_vcpus());
> +			if (err) {
> +				kvm_err("kvm_arch_timer: error setting vcpu affinity\n");
> +				goto out_free_irq;
> +			}
> +		}
> +
> +		kvm_debug("physical timer IRQ%d\n", host_ptimer_irq);
> +	}
> +
>  	cpuhp_setup_state(CPUHP_AP_KVM_ARM_TIMER_STARTING,
>  			  "kvm/arm/timer:starting", kvm_timer_starting_cpu,
>  			  kvm_timer_dying_cpu);
> @@ -897,8 +1003,10 @@ bool kvm_arch_timer_get_input_level(int vintid)
>  
>  	if (vintid == vcpu_vtimer(vcpu)->irq.irq)
>  		timer = vcpu_vtimer(vcpu);
> +	else if (vintid == vcpu_ptimer(vcpu)->irq.irq)
> +		timer = vcpu_ptimer(vcpu);
>  	else
> -		BUG(); /* We only map the vtimer so far */
> +		BUG();
>  
>  	return kvm_timer_should_fire(timer);
>  }
> @@ -907,6 +1015,7 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
>  {
>  	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
>  	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> +	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
>  	int ret;
>  
>  	if (timer->enabled)
> @@ -929,6 +1038,13 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
>  	if (ret)
>  		return ret;
>  
> +	if (has_vhe()) {
> +		ret = kvm_vgic_map_phys_irq(vcpu, host_ptimer_irq, ptimer->irq.irq,
> +					    kvm_arch_timer_get_input_level);
> +		if (ret)
> +			return ret;
> +	}
> +
>  no_vgic:
>  	timer->enabled = 1;
>  	return 0;
> @@ -951,7 +1067,7 @@ void kvm_timer_init_vhe(void)
>  	 * Physical counter access is allowed.
>  	 */
This trimmed comment and the comment for the function still state that physical
timer access is trapped from the guest. I think both comments should be updated
to reflect that that isn't the case anymore.
>  	val = read_sysreg(cnthctl_el2);
> -	val &= ~(CNTHCTL_EL1PCEN << cnthctl_shift);
> +	val |= (CNTHCTL_EL1PCEN << cnthctl_shift);
>  	val |= (CNTHCTL_EL1PCTEN << cnthctl_shift);
>  	write_sysreg(val, cnthctl_el2);
>  }

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 11/14] KVM: arm/arm64: timer: Rework data structures for multiple timers
  2019-02-18 15:10   ` André Przywara
@ 2019-02-19 12:27     ` Christoffer Dall
  0 siblings, 0 replies; 33+ messages in thread
From: Christoffer Dall @ 2019-02-19 12:27 UTC (permalink / raw)
  To: André Przywara; +Cc: Marc Zyngier, kvmarm, linux-arm-kernel, kvm

On Mon, Feb 18, 2019 at 03:10:16PM +0000, André Przywara wrote:
> On Thu, 24 Jan 2019 15:00:29 +0100
> Christoffer Dall <christoffer.dall@arm.com> wrote:
> 
> Hi,
> 
> I already looked at most of these patches earlier, without finding
> serious issues, but figured I would give those without any Reviewed-by:
> or Acked-by: tags a closer look.
> (This patch just carries a S-o-b: tag from Marc in the kvm-arm git repo.)
> 
> > Prepare for having 4 timer data structures (2 for now).
> > 
> > Change loaded to an enum so that we know not just whether *some* state
> > is loaded on the CPU, but also *which* state is loaded.
> > 
> > Move loaded to the cpu data structure and not the individual timer
> > structure, in preparation for assigning the EL1 phys timer as well.
> > 
> > Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
> > Acked-by: Marc Zyngier <marc.zyngier@arm.com>
> > ---
> >  include/kvm/arm_arch_timer.h | 44 ++++++++++++++-------------
> >  virt/kvm/arm/arch_timer.c    | 58 +++++++++++++++++++-----------------
> >  2 files changed, 54 insertions(+), 48 deletions(-)
> > 
> > diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
> > index d26b7fde9935..d40fe57a2d0d 100644
> > --- a/include/kvm/arm_arch_timer.h
> > +++ b/include/kvm/arm_arch_timer.h
> > @@ -36,6 +36,8 @@ enum kvm_arch_timer_regs {
> >  };
> >  
> >  struct arch_timer_context {
> > +	struct kvm_vcpu			*vcpu;
> > +
> >  	/* Registers: control register, timer value */
> >  	u32				cnt_ctl;
> >  	u64				cnt_cval;
> > @@ -43,32 +45,34 @@ struct arch_timer_context {
> >  	/* Timer IRQ */
> >  	struct kvm_irq_level		irq;
> >  
> > -	/*
> > -	 * We have multiple paths which can save/restore the timer state
> > -	 * onto the hardware, so we need some way of keeping track of
> > -	 * where the latest state is.
> > -	 *
> > -	 * loaded == true:  State is loaded on the hardware registers.
> > -	 * loaded == false: State is stored in memory.
> > -	 */
> > -	bool			loaded;
> > -
> >  	/* Virtual offset */
> > -	u64			cntvoff;
> > +	u64				cntvoff;
> > +
> > +	/* Emulated Timer (may be unused) */
> > +	struct hrtimer			hrtimer;
> > +};
> > +
> > +enum loaded_timer_state {
> > +	TIMER_NOT_LOADED,
> > +	TIMER_EL1_LOADED,
> 
> So this gets reverted in PATCH 13/14, and I don't see it reappearing in
> the nv series later on.
> Is that just needed for assigning the phys timer in the next patch, and
> gets obsolete with the timer_map?
> Or is this a rebase artefact and we don't actually need this?

I think this is a rebase problem and we could have optimized this out to
reduce the patch diff.  The end result is the same though.

> 
> The rest of the patch looks like valid transformations to me.
> 
Thanks for having a look.

    Christoffer

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 12/14] KVM: arm/arm64: arch_timer: Assign the phys timer on VHE systems
  2019-02-18 15:10   ` André Przywara
@ 2019-02-19 12:43     ` Christoffer Dall
  2019-02-20 17:58       ` Andre Przywara
  0 siblings, 1 reply; 33+ messages in thread
From: Christoffer Dall @ 2019-02-19 12:43 UTC (permalink / raw)
  To: André Przywara; +Cc: Marc Zyngier, kvmarm, linux-arm-kernel, kvm

On Mon, Feb 18, 2019 at 03:10:49PM +0000, André Przywara wrote:
> On Thu, 24 Jan 2019 15:00:30 +0100
> Christoffer Dall <christoffer.dall@arm.com> wrote:
> 
> Hi,
> 
> > VHE systems don't have to emulate the physical timer, we can simply
> > assigne the EL1 physical timer directly to the VM as the host always
> > uses the EL2 timers.
> > 
> > In order to minimize the amount of cruft, AArch32 gets definitions for
> > the physical timer too, but is should be generally unused on this
> > architecture.
> > 
> > Co-written with Marc Zyngier <marc.zyngier@arm.com>
> > 
> > Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> > Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
> > ---
> >  arch/arm/include/asm/kvm_hyp.h |   4 +
> >  include/kvm/arm_arch_timer.h   |   6 +
> >  virt/kvm/arm/arch_timer.c      | 206 ++++++++++++++++++++++++++-------
> >  3 files changed, 171 insertions(+), 45 deletions(-)
> > 
> > diff --git a/arch/arm/include/asm/kvm_hyp.h b/arch/arm/include/asm/kvm_hyp.h
> > index e93a0cac9add..87bcd18df8d5 100644
> > --- a/arch/arm/include/asm/kvm_hyp.h
> > +++ b/arch/arm/include/asm/kvm_hyp.h
> > @@ -40,6 +40,7 @@
> >  #define TTBR1		__ACCESS_CP15_64(1, c2)
> >  #define VTTBR		__ACCESS_CP15_64(6, c2)
> >  #define PAR		__ACCESS_CP15_64(0, c7)
> > +#define CNTP_CVAL	__ACCESS_CP15_64(2, c14)
> >  #define CNTV_CVAL	__ACCESS_CP15_64(3, c14)
> >  #define CNTVOFF		__ACCESS_CP15_64(4, c14)
> >  
> > @@ -85,6 +86,7 @@
> >  #define TID_PRIV	__ACCESS_CP15(c13, 0, c0, 4)
> >  #define HTPIDR		__ACCESS_CP15(c13, 4, c0, 2)
> >  #define CNTKCTL		__ACCESS_CP15(c14, 0, c1, 0)
> > +#define CNTP_CTL	__ACCESS_CP15(c14, 0, c2, 1)
> >  #define CNTV_CTL	__ACCESS_CP15(c14, 0, c3, 1)
> >  #define CNTHCTL		__ACCESS_CP15(c14, 4, c1, 0)
> >  
> > @@ -94,6 +96,8 @@
> >  #define read_sysreg_el0(r)		read_sysreg(r##_el0)
> >  #define write_sysreg_el0(v, r)		write_sysreg(v, r##_el0)
> >  
> > +#define cntp_ctl_el0			CNTP_CTL
> > +#define cntp_cval_el0			CNTP_CVAL
> >  #define cntv_ctl_el0			CNTV_CTL
> >  #define cntv_cval_el0			CNTV_CVAL
> >  #define cntvoff_el2			CNTVOFF
> > diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
> > index d40fe57a2d0d..722e0481f310 100644
> > --- a/include/kvm/arm_arch_timer.h
> > +++ b/include/kvm/arm_arch_timer.h
> > @@ -50,6 +50,10 @@ struct arch_timer_context {
> >  
> >  	/* Emulated Timer (may be unused) */
> >  	struct hrtimer			hrtimer;
> > +
> > +	/* Duplicated state from arch_timer.c for convenience */
> > +	u32				host_timer_irq;
> > +	u32				host_timer_irq_flags;
> >  };
> >  
> >  enum loaded_timer_state {
> > @@ -107,6 +111,8 @@ bool kvm_arch_timer_get_input_level(int vintid);
> >  #define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.timers[TIMER_VTIMER])
> >  #define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.timers[TIMER_PTIMER])
> >  
> > +#define arch_timer_ctx_index(ctx)	((ctx) - vcpu_timer((ctx)->vcpu)->timers)
> > +
> >  u64 kvm_arm_timer_read_sysreg(struct kvm_vcpu *vcpu,
> >  			      enum kvm_arch_timers tmr,
> >  			      enum kvm_arch_timer_regs treg);
> > diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> > index 8b0eca5fbad1..eed8f48fbf9b 100644
> > --- a/virt/kvm/arm/arch_timer.c
> > +++ b/virt/kvm/arm/arch_timer.c
> > @@ -35,7 +35,9 @@
> >  
> >  static struct timecounter *timecounter;
> >  static unsigned int host_vtimer_irq;
> > +static unsigned int host_ptimer_irq;
> >  static u32 host_vtimer_irq_flags;
> > +static u32 host_ptimer_irq_flags;
> >  
> >  static DEFINE_STATIC_KEY_FALSE(has_gic_active_state);
> >  
> > @@ -86,20 +88,24 @@ static void soft_timer_cancel(struct hrtimer *hrt)
> >  static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
> >  {
> >  	struct kvm_vcpu *vcpu = *(struct kvm_vcpu **)dev_id;
> > -	struct arch_timer_context *vtimer;
> > +	struct arch_timer_context *ctx;
> >  
> >  	/*
> >  	 * We may see a timer interrupt after vcpu_put() has been called which
> >  	 * sets the CPU's vcpu pointer to NULL, because even though the timer
> > -	 * has been disabled in vtimer_save_state(), the hardware interrupt
> > +	 * has been disabled in timer_save_state(), the hardware interrupt
> >  	 * signal may not have been retired from the interrupt controller yet.
> >  	 */
> >  	if (!vcpu)
> >  		return IRQ_HANDLED;
> >  
> > -	vtimer = vcpu_vtimer(vcpu);
> > -	if (kvm_timer_should_fire(vtimer))
> > -		kvm_timer_update_irq(vcpu, true, vtimer);
> > +	if (irq == host_vtimer_irq)
> > +		ctx = vcpu_vtimer(vcpu);
> > +	else
> > +		ctx = vcpu_ptimer(vcpu);
> > +
> > +	if (kvm_timer_should_fire(ctx))
> > +		kvm_timer_update_irq(vcpu, true, ctx);
> >  
> >  	if (userspace_irqchip(vcpu->kvm) &&
> >  	    !static_branch_unlikely(&has_gic_active_state))
> > @@ -208,13 +214,25 @@ static enum hrtimer_restart kvm_phys_timer_expire(struct hrtimer *hrt)
> >  static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx)
> >  {
> >  	struct arch_timer_cpu *timer = vcpu_timer(timer_ctx->vcpu);
> > +	enum kvm_arch_timers index = arch_timer_ctx_index(timer_ctx);
> >  	u64 cval, now;
> >  
> >  	if (timer->loaded == TIMER_EL1_LOADED) {
> > -		u32 cnt_ctl;
> > +		u32 cnt_ctl = 0;
> > +
> > +		switch (index) {
> > +		case TIMER_VTIMER:
> > +			cnt_ctl = read_sysreg_el0(cntv_ctl);
> > +			break;
> > +		case TIMER_PTIMER:
> > +			cnt_ctl = read_sysreg_el0(cntp_ctl);
> > +			break;
> > +		case NR_KVM_TIMERS:
> > +			/* GCC is braindead */
> > +			cnt_ctl = 0;
> > +			break;
> > +		}
> >  
> > -		/* Only the virtual timer can be loaded so far */
> > -		cnt_ctl = read_sysreg_el0(cntv_ctl);
> >  		return  (cnt_ctl & ARCH_TIMER_CTRL_ENABLE) &&
> >  		        (cnt_ctl & ARCH_TIMER_CTRL_IT_STAT) &&
> >  		       !(cnt_ctl & ARCH_TIMER_CTRL_IT_MASK);
> > @@ -310,7 +328,7 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
> >  		return;
> >  
> >  	/*
> > -	 * The vtimer virtual interrupt is a 'mapped' interrupt, meaning part
> > +	 * If the timer virtual interrupt is a 'mapped' interrupt, part
> >  	 * of its lifecycle is offloaded to the hardware, and we therefore may
> >  	 * not have lowered the irq.level value before having to signal a new
> >  	 * interrupt, but have to signal an interrupt every time the level is
> > @@ -319,31 +337,55 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
> >  	level = kvm_timer_should_fire(vtimer);
> >  	kvm_timer_update_irq(vcpu, level, vtimer);
> >  
> > +	if (has_vhe()) {
> 
> Not really critical, but wouldn't it be cleaner to use "if
> (host_ptimer_irq > 0)" here to check if we map the phys timer as well?
> This is at least how we originally derive the decision to initialise
> everything in kvm_timer_hyp_init() below. Applies to the other instances
> of "if (has_vhe())" as well.
> But I guess we use has_vhe() because it's a static key? In this case
> would it be worth to define some cosmetic wrapper, to improve readability?
> 
> > +		level = kvm_timer_should_fire(ptimer);
> > +		kvm_timer_update_irq(vcpu, level, ptimer);
> > +
> > +		return;
> > +	}
> > +
> >  	phys_timer_emulate(vcpu);
> >  
> >  	if (kvm_timer_should_fire(ptimer) != ptimer->irq.level)
> >  		kvm_timer_update_irq(vcpu, !ptimer->irq.level, ptimer);
> >  }
> >  
> > -static void vtimer_save_state(struct kvm_vcpu *vcpu)
> > +static void timer_save_state(struct arch_timer_context *ctx)
> >  {
> > -	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
> > -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> > +	struct arch_timer_cpu *timer = vcpu_timer(ctx->vcpu);
> > +	enum kvm_arch_timers index = arch_timer_ctx_index(ctx);
> >  	unsigned long flags;
> >  
> > +	if (!timer->enabled)
> > +		return;
> > +
> >  	local_irq_save(flags);
> >  
> >  	if (timer->loaded == TIMER_NOT_LOADED)
> >  		goto out;
> >  
> > -	if (timer->enabled) {
> > -		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> > -		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
> > -	}
> > +	switch (index) {
> > +	case TIMER_VTIMER:
> > +		ctx->cnt_ctl = read_sysreg_el0(cntv_ctl);
> > +		ctx->cnt_cval = read_sysreg_el0(cntv_cval);
> >  
> > -	/* Disable the virtual timer */
> > -	write_sysreg_el0(0, cntv_ctl);
> > -	isb();
> > +		/* Disable the timer */
> > +		write_sysreg_el0(0, cntv_ctl);
> > +		isb();
> > +
> > +		break;
> > +	case TIMER_PTIMER:
> > +		ctx->cnt_ctl = read_sysreg_el0(cntp_ctl);
> > +		ctx->cnt_cval = read_sysreg_el0(cntp_cval);
> > +
> > +		/* Disable the timer */
> > +		write_sysreg_el0(0, cntp_ctl);
> > +		isb();
> > +
> > +		break;
> > +	case NR_KVM_TIMERS:
> > +		break; /* GCC is braindead */
> > +	}
> >  
> >  	timer->loaded = TIMER_NOT_LOADED;
> >  out:
> > @@ -382,21 +424,33 @@ static void kvm_timer_unblocking(struct kvm_vcpu *vcpu)
> >  	soft_timer_cancel(&timer->bg_timer);
> >  }
> >  
> > -static void vtimer_restore_state(struct kvm_vcpu *vcpu)
> > +static void timer_restore_state(struct arch_timer_context *ctx)
> >  {
> > -	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
> > -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> > +	struct arch_timer_cpu *timer = vcpu_timer(ctx->vcpu);
> > +	enum kvm_arch_timers index = arch_timer_ctx_index(ctx);
> >  	unsigned long flags;
> >  
> > +	if (!timer->enabled)
> > +		return;
> > +
> >  	local_irq_save(flags);
> >  
> >  	if (timer->loaded == TIMER_EL1_LOADED)
> >  		goto out;
> >  
> > -	if (timer->enabled) {
> > -		write_sysreg_el0(vtimer->cnt_cval, cntv_cval);
> > +	switch (index) {
> > +	case TIMER_VTIMER:
> > +		write_sysreg_el0(ctx->cnt_cval, cntv_cval);
> > +		isb();
> > +		write_sysreg_el0(ctx->cnt_ctl, cntv_ctl);
> > +		break;
> > +	case TIMER_PTIMER:
> > +		write_sysreg_el0(ctx->cnt_cval, cntp_cval);
> >  		isb();
> > -		write_sysreg_el0(vtimer->cnt_ctl, cntv_ctl);
> > +		write_sysreg_el0(ctx->cnt_ctl, cntp_ctl);
> > +		break;
> > +	case NR_KVM_TIMERS:
> > +		break; /* GCC is braindead */
> >  	}
> >  
> >  	timer->loaded = TIMER_EL1_LOADED;
> > @@ -419,23 +473,23 @@ static void set_cntvoff(u64 cntvoff)
> >  	kvm_call_hyp(__kvm_timer_set_cntvoff, low, high);
> >  }
> >  
> > -static inline void set_vtimer_irq_phys_active(struct kvm_vcpu *vcpu, bool active)
> > +static inline void set_timer_irq_phys_active(struct arch_timer_context *ctx, bool active)
> >  {
> >  	int r;
> > -	r = irq_set_irqchip_state(host_vtimer_irq, IRQCHIP_STATE_ACTIVE, active);
> > +	r = irq_set_irqchip_state(ctx->host_timer_irq, IRQCHIP_STATE_ACTIVE, active);
> >  	WARN_ON(r);
> >  }
> >  
> > -static void kvm_timer_vcpu_load_gic(struct kvm_vcpu *vcpu)
> > +static void kvm_timer_vcpu_load_gic(struct arch_timer_context *ctx)
> >  {
> > -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> > +	struct kvm_vcpu *vcpu = ctx->vcpu;
> >  	bool phys_active;
> >  
> >  	if (irqchip_in_kernel(vcpu->kvm))
> > -		phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
> > +		phys_active = kvm_vgic_map_is_active(vcpu, ctx->irq.irq);
> >  	else
> > -		phys_active = vtimer->irq.level;
> > -	set_vtimer_irq_phys_active(vcpu, phys_active);
> > +		phys_active = ctx->irq.level;
> > +	set_timer_irq_phys_active(ctx, phys_active);
> >  }
> >  
> >  static void kvm_timer_vcpu_load_nogic(struct kvm_vcpu *vcpu)
> > @@ -467,14 +521,22 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
> >  	if (unlikely(!timer->enabled))
> >  		return;
> >  
> > -	if (static_branch_likely(&has_gic_active_state))
> > -		kvm_timer_vcpu_load_gic(vcpu);
> > -	else
> > +	if (static_branch_likely(&has_gic_active_state)) {
> > +		kvm_timer_vcpu_load_gic(vtimer);
> > +		if (has_vhe())
> > +			kvm_timer_vcpu_load_gic(ptimer);
> > +	} else {
> >  		kvm_timer_vcpu_load_nogic(vcpu);
> > +	}
> >  
> >  	set_cntvoff(vtimer->cntvoff);
> >  
> > -	vtimer_restore_state(vcpu);
> > +	timer_restore_state(vtimer);
> > +
> > +	if (has_vhe()) {
> > +		timer_restore_state(ptimer);
> > +		return;
> > +	}
> >  
> >  	/* Set the background timer for the physical timer emulation. */
> >  	phys_timer_emulate(vcpu);
> > @@ -506,12 +568,17 @@ bool kvm_timer_should_notify_user(struct kvm_vcpu *vcpu)
> >  void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
> >  {
> >  	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
> > +	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> >  	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
> >  
> >  	if (unlikely(!timer->enabled))
> >  		return;
> >  
> > -	vtimer_save_state(vcpu);
> > +	timer_save_state(vtimer);
> > +	if (has_vhe()) {
> > +		timer_save_state(ptimer);
> > +		return;
> > +	}
> >  
> >  	/*
> >  	 * Cancel the physical timer emulation, because the only case where we
> > @@ -534,8 +601,7 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
> >  	 * counter of non-VHE case. For VHE, the virtual counter uses a fixed
> >  	 * virtual offset of zero, so no need to zero CNTVOFF_EL2 register.
> >  	 */
> > -	if (!has_vhe())
> > -		set_cntvoff(0);
> > +	set_cntvoff(0);
> >  }
> >  
> >  /*
> > @@ -550,7 +616,7 @@ static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu)
> >  	if (!kvm_timer_should_fire(vtimer)) {
> >  		kvm_timer_update_irq(vcpu, false, vtimer);
> >  		if (static_branch_likely(&has_gic_active_state))
> > -			set_vtimer_irq_phys_active(vcpu, false);
> > +			set_timer_irq_phys_active(vtimer, false);
> >  		else
> >  			enable_percpu_irq(host_vtimer_irq, host_vtimer_irq_flags);
> >  	}
> > @@ -625,7 +691,12 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
> >  	ptimer->hrtimer.function = kvm_phys_timer_expire;
> >  
> >  	vtimer->irq.irq = default_vtimer_irq.irq;
> > +	vtimer->host_timer_irq = host_vtimer_irq;
> > +	vtimer->host_timer_irq_flags = host_vtimer_irq_flags;
> > +
> >  	ptimer->irq.irq = default_ptimer_irq.irq;
> > +	ptimer->host_timer_irq = host_ptimer_irq;
> > +	ptimer->host_timer_irq_flags = host_ptimer_irq_flags;
> >  
> >  	vtimer->vcpu = vcpu;
> >  	ptimer->vcpu = vcpu;
> > @@ -634,6 +705,7 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
> >  static void kvm_timer_init_interrupt(void *info)
> >  {
> >  	enable_percpu_irq(host_vtimer_irq, host_vtimer_irq_flags);
> > +	enable_percpu_irq(host_ptimer_irq, host_ptimer_irq_flags);
> 
> Shouldn't we only enable host_ptimer_irq() if we actually pass this on
> here? So either guarded by has_vhe() or (host_ptimer_irq > 0)?
> Otherwise we would enable IRQ 0?
> 

I think the right fix is to raise an error if a VHE system doesn't give
us a valid physical irq number during init, and then leave the checks
for has_vhe() here.

Thanks,

    Christoffer

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 12/14] KVM: arm/arm64: arch_timer: Assign the phys timer on VHE systems
  2019-02-19 11:39   ` Alexandru Elisei
@ 2019-02-19 13:03     ` Christoffer Dall
  0 siblings, 0 replies; 33+ messages in thread
From: Christoffer Dall @ 2019-02-19 13:03 UTC (permalink / raw)
  To: Alexandru Elisei; +Cc: Marc Zyngier, kvmarm, linux-arm-kernel, kvm

On Tue, Feb 19, 2019 at 11:39:50AM +0000, Alexandru Elisei wrote:
> 
> On 1/24/19 2:00 PM, Christoffer Dall wrote:
> > VHE systems don't have to emulate the physical timer, we can simply
> > assigne the EL1 physical timer directly to the VM as the host always
> > uses the EL2 timers.
> >
> > In order to minimize the amount of cruft, AArch32 gets definitions for
> > the physical timer too, but is should be generally unused on this
> > architecture.
> >
> > Co-written with Marc Zyngier <marc.zyngier@arm.com>
> >
> > Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> > Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
> > ---
> >  arch/arm/include/asm/kvm_hyp.h |   4 +
> >  include/kvm/arm_arch_timer.h   |   6 +
> >  virt/kvm/arm/arch_timer.c      | 206 ++++++++++++++++++++++++++-------
> >  3 files changed, 171 insertions(+), 45 deletions(-)
> >
> > diff --git a/arch/arm/include/asm/kvm_hyp.h b/arch/arm/include/asm/kvm_hyp.h
> > index e93a0cac9add..87bcd18df8d5 100644
> > --- a/arch/arm/include/asm/kvm_hyp.h
> > +++ b/arch/arm/include/asm/kvm_hyp.h
> > @@ -40,6 +40,7 @@
> >  #define TTBR1		__ACCESS_CP15_64(1, c2)
> >  #define VTTBR		__ACCESS_CP15_64(6, c2)
> >  #define PAR		__ACCESS_CP15_64(0, c7)
> > +#define CNTP_CVAL	__ACCESS_CP15_64(2, c14)
> >  #define CNTV_CVAL	__ACCESS_CP15_64(3, c14)
> >  #define CNTVOFF		__ACCESS_CP15_64(4, c14)
> >  
> > @@ -85,6 +86,7 @@
> >  #define TID_PRIV	__ACCESS_CP15(c13, 0, c0, 4)
> >  #define HTPIDR		__ACCESS_CP15(c13, 4, c0, 2)
> >  #define CNTKCTL		__ACCESS_CP15(c14, 0, c1, 0)
> > +#define CNTP_CTL	__ACCESS_CP15(c14, 0, c2, 1)
> >  #define CNTV_CTL	__ACCESS_CP15(c14, 0, c3, 1)
> >  #define CNTHCTL		__ACCESS_CP15(c14, 4, c1, 0)
> >  
> > @@ -94,6 +96,8 @@
> >  #define read_sysreg_el0(r)		read_sysreg(r##_el0)
> >  #define write_sysreg_el0(v, r)		write_sysreg(v, r##_el0)
> >  
> > +#define cntp_ctl_el0			CNTP_CTL
> > +#define cntp_cval_el0			CNTP_CVAL
> >  #define cntv_ctl_el0			CNTV_CTL
> >  #define cntv_cval_el0			CNTV_CVAL
> >  #define cntvoff_el2			CNTVOFF
> > diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
> > index d40fe57a2d0d..722e0481f310 100644
> > --- a/include/kvm/arm_arch_timer.h
> > +++ b/include/kvm/arm_arch_timer.h
> > @@ -50,6 +50,10 @@ struct arch_timer_context {
> >  
> >  	/* Emulated Timer (may be unused) */
> >  	struct hrtimer			hrtimer;
> > +
> > +	/* Duplicated state from arch_timer.c for convenience */
> > +	u32				host_timer_irq;
> > +	u32				host_timer_irq_flags;
> >  };
> >  
> >  enum loaded_timer_state {
> > @@ -107,6 +111,8 @@ bool kvm_arch_timer_get_input_level(int vintid);
> >  #define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.timers[TIMER_VTIMER])
> >  #define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.timers[TIMER_PTIMER])
> >  
> > +#define arch_timer_ctx_index(ctx)	((ctx) - vcpu_timer((ctx)->vcpu)->timers)
> > +
> >  u64 kvm_arm_timer_read_sysreg(struct kvm_vcpu *vcpu,
> >  			      enum kvm_arch_timers tmr,
> >  			      enum kvm_arch_timer_regs treg);
> > diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> > index 8b0eca5fbad1..eed8f48fbf9b 100644
> > --- a/virt/kvm/arm/arch_timer.c
> > +++ b/virt/kvm/arm/arch_timer.c
> > @@ -35,7 +35,9 @@
> >  
> >  static struct timecounter *timecounter;
> >  static unsigned int host_vtimer_irq;
> > +static unsigned int host_ptimer_irq;
> >  static u32 host_vtimer_irq_flags;
> > +static u32 host_ptimer_irq_flags;
> >  
> >  static DEFINE_STATIC_KEY_FALSE(has_gic_active_state);
> >  
> > @@ -86,20 +88,24 @@ static void soft_timer_cancel(struct hrtimer *hrt)
> >  static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
> >  {
> >  	struct kvm_vcpu *vcpu = *(struct kvm_vcpu **)dev_id;
> > -	struct arch_timer_context *vtimer;
> > +	struct arch_timer_context *ctx;
> >  
> >  	/*
> >  	 * We may see a timer interrupt after vcpu_put() has been called which
> >  	 * sets the CPU's vcpu pointer to NULL, because even though the timer
> > -	 * has been disabled in vtimer_save_state(), the hardware interrupt
> > +	 * has been disabled in timer_save_state(), the hardware interrupt
> >  	 * signal may not have been retired from the interrupt controller yet.
> >  	 */
> >  	if (!vcpu)
> >  		return IRQ_HANDLED;
> >  
> > -	vtimer = vcpu_vtimer(vcpu);
> > -	if (kvm_timer_should_fire(vtimer))
> > -		kvm_timer_update_irq(vcpu, true, vtimer);
> > +	if (irq == host_vtimer_irq)
> > +		ctx = vcpu_vtimer(vcpu);
> > +	else
> > +		ctx = vcpu_ptimer(vcpu);
> > +
> > +	if (kvm_timer_should_fire(ctx))
> > +		kvm_timer_update_irq(vcpu, true, ctx);
> >  
> >  	if (userspace_irqchip(vcpu->kvm) &&
> >  	    !static_branch_unlikely(&has_gic_active_state))
> > @@ -208,13 +214,25 @@ static enum hrtimer_restart kvm_phys_timer_expire(struct hrtimer *hrt)
> >  static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx)
> >  {
> >  	struct arch_timer_cpu *timer = vcpu_timer(timer_ctx->vcpu);
> > +	enum kvm_arch_timers index = arch_timer_ctx_index(timer_ctx);
> >  	u64 cval, now;
> >  
> >  	if (timer->loaded == TIMER_EL1_LOADED) {
> > -		u32 cnt_ctl;
> > +		u32 cnt_ctl = 0;
> > +
> > +		switch (index) {
> > +		case TIMER_VTIMER:
> > +			cnt_ctl = read_sysreg_el0(cntv_ctl);
> > +			break;
> > +		case TIMER_PTIMER:
> > +			cnt_ctl = read_sysreg_el0(cntp_ctl);
> > +			break;
> > +		case NR_KVM_TIMERS:
> > +			/* GCC is braindead */
> > +			cnt_ctl = 0;
> > +			break;
> > +		}
> >  
> > -		/* Only the virtual timer can be loaded so far */
> > -		cnt_ctl = read_sysreg_el0(cntv_ctl);
> >  		return  (cnt_ctl & ARCH_TIMER_CTRL_ENABLE) &&
> >  		        (cnt_ctl & ARCH_TIMER_CTRL_IT_STAT) &&
> >  		       !(cnt_ctl & ARCH_TIMER_CTRL_IT_MASK);
> > @@ -310,7 +328,7 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
> >  		return;
> >  
> >  	/*
> > -	 * The vtimer virtual interrupt is a 'mapped' interrupt, meaning part
> > +	 * If the timer virtual interrupt is a 'mapped' interrupt, part
> >  	 * of its lifecycle is offloaded to the hardware, and we therefore may
> >  	 * not have lowered the irq.level value before having to signal a new
> >  	 * interrupt, but have to signal an interrupt every time the level is
> > @@ -319,31 +337,55 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
> >  	level = kvm_timer_should_fire(vtimer);
> >  	kvm_timer_update_irq(vcpu, level, vtimer);
> >  
> > +	if (has_vhe()) {
> > +		level = kvm_timer_should_fire(ptimer);
> > +		kvm_timer_update_irq(vcpu, level, ptimer);
> > +
> > +		return;
> > +	}
> > +
> >  	phys_timer_emulate(vcpu);
> >  
> >  	if (kvm_timer_should_fire(ptimer) != ptimer->irq.level)
> >  		kvm_timer_update_irq(vcpu, !ptimer->irq.level, ptimer);
> >  }
> >  
> > -static void vtimer_save_state(struct kvm_vcpu *vcpu)
> > +static void timer_save_state(struct arch_timer_context *ctx)
> >  {
> > -	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
> > -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> > +	struct arch_timer_cpu *timer = vcpu_timer(ctx->vcpu);
> > +	enum kvm_arch_timers index = arch_timer_ctx_index(ctx);
> >  	unsigned long flags;
> >  
> > +	if (!timer->enabled)
> > +		return;
> > +
> >  	local_irq_save(flags);
> >  
> >  	if (timer->loaded == TIMER_NOT_LOADED)
> >  		goto out;
> >  
> > -	if (timer->enabled) {
> > -		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> > -		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
> > -	}
> > +	switch (index) {
> > +	case TIMER_VTIMER:
> > +		ctx->cnt_ctl = read_sysreg_el0(cntv_ctl);
> > +		ctx->cnt_cval = read_sysreg_el0(cntv_cval);
> >  
> > -	/* Disable the virtual timer */
> > -	write_sysreg_el0(0, cntv_ctl);
> > -	isb();
> > +		/* Disable the timer */
> > +		write_sysreg_el0(0, cntv_ctl);
> > +		isb();
> > +
> > +		break;
> > +	case TIMER_PTIMER:
> > +		ctx->cnt_ctl = read_sysreg_el0(cntp_ctl);
> > +		ctx->cnt_cval = read_sysreg_el0(cntp_cval);
> > +
> > +		/* Disable the timer */
> > +		write_sysreg_el0(0, cntp_ctl);
> > +		isb();
> > +
> > +		break;
> > +	case NR_KVM_TIMERS:
> > +		break; /* GCC is braindead */
> > +	}
> >  
> >  	timer->loaded = TIMER_NOT_LOADED;
> >  out:
> > @@ -382,21 +424,33 @@ static void kvm_timer_unblocking(struct kvm_vcpu *vcpu)
> >  	soft_timer_cancel(&timer->bg_timer);
> >  }
> >  
> > -static void vtimer_restore_state(struct kvm_vcpu *vcpu)
> > +static void timer_restore_state(struct arch_timer_context *ctx)
> >  {
> > -	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
> > -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> > +	struct arch_timer_cpu *timer = vcpu_timer(ctx->vcpu);
> > +	enum kvm_arch_timers index = arch_timer_ctx_index(ctx);
> >  	unsigned long flags;
> >  
> > +	if (!timer->enabled)
> > +		return;
> > +
> >  	local_irq_save(flags);
> >  
> >  	if (timer->loaded == TIMER_EL1_LOADED)
> >  		goto out;
> >  
> > -	if (timer->enabled) {
> > -		write_sysreg_el0(vtimer->cnt_cval, cntv_cval);
> > +	switch (index) {
> > +	case TIMER_VTIMER:
> > +		write_sysreg_el0(ctx->cnt_cval, cntv_cval);
> > +		isb();
> > +		write_sysreg_el0(ctx->cnt_ctl, cntv_ctl);
> > +		break;
> > +	case TIMER_PTIMER:
> > +		write_sysreg_el0(ctx->cnt_cval, cntp_cval);
> >  		isb();
> > -		write_sysreg_el0(vtimer->cnt_ctl, cntv_ctl);
> > +		write_sysreg_el0(ctx->cnt_ctl, cntp_ctl);
> > +		break;
> > +	case NR_KVM_TIMERS:
> > +		break; /* GCC is braindead */
> >  	}
> >  
> >  	timer->loaded = TIMER_EL1_LOADED;
> > @@ -419,23 +473,23 @@ static void set_cntvoff(u64 cntvoff)
> >  	kvm_call_hyp(__kvm_timer_set_cntvoff, low, high);
> >  }
> >  
> > -static inline void set_vtimer_irq_phys_active(struct kvm_vcpu *vcpu, bool active)
> > +static inline void set_timer_irq_phys_active(struct arch_timer_context *ctx, bool active)
> >  {
> >  	int r;
> > -	r = irq_set_irqchip_state(host_vtimer_irq, IRQCHIP_STATE_ACTIVE, active);
> > +	r = irq_set_irqchip_state(ctx->host_timer_irq, IRQCHIP_STATE_ACTIVE, active);
> >  	WARN_ON(r);
> >  }
> >  
> > -static void kvm_timer_vcpu_load_gic(struct kvm_vcpu *vcpu)
> > +static void kvm_timer_vcpu_load_gic(struct arch_timer_context *ctx)
> >  {
> > -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> > +	struct kvm_vcpu *vcpu = ctx->vcpu;
> >  	bool phys_active;
> >  
> >  	if (irqchip_in_kernel(vcpu->kvm))
> > -		phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
> > +		phys_active = kvm_vgic_map_is_active(vcpu, ctx->irq.irq);
> >  	else
> > -		phys_active = vtimer->irq.level;
> > -	set_vtimer_irq_phys_active(vcpu, phys_active);
> > +		phys_active = ctx->irq.level;
> > +	set_timer_irq_phys_active(ctx, phys_active);
> >  }
> >  
> >  static void kvm_timer_vcpu_load_nogic(struct kvm_vcpu *vcpu)
> > @@ -467,14 +521,22 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
> >  	if (unlikely(!timer->enabled))
> >  		return;
> >  
> > -	if (static_branch_likely(&has_gic_active_state))
> > -		kvm_timer_vcpu_load_gic(vcpu);
> > -	else
> > +	if (static_branch_likely(&has_gic_active_state)) {
> > +		kvm_timer_vcpu_load_gic(vtimer);
> > +		if (has_vhe())
> > +			kvm_timer_vcpu_load_gic(ptimer);
> > +	} else {
> >  		kvm_timer_vcpu_load_nogic(vcpu);
> > +	}
> >  
> >  	set_cntvoff(vtimer->cntvoff);
> >  
> > -	vtimer_restore_state(vcpu);
> > +	timer_restore_state(vtimer);
> > +
> > +	if (has_vhe()) {
> > +		timer_restore_state(ptimer);
> > +		return;
> > +	}
> >  
> >  	/* Set the background timer for the physical timer emulation. */
> >  	phys_timer_emulate(vcpu);
> > @@ -506,12 +568,17 @@ bool kvm_timer_should_notify_user(struct kvm_vcpu *vcpu)
> >  void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
> >  {
> >  	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
> > +	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> >  	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
> >  
> >  	if (unlikely(!timer->enabled))
> >  		return;
> >  
> > -	vtimer_save_state(vcpu);
> > +	timer_save_state(vtimer);
> > +	if (has_vhe()) {
> > +		timer_save_state(ptimer);
> > +		return;
> > +	}
> >  
> >  	/*
> >  	 * Cancel the physical timer emulation, because the only case where we
> > @@ -534,8 +601,7 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
> >  	 * counter of non-VHE case. For VHE, the virtual counter uses a fixed
> >  	 * virtual offset of zero, so no need to zero CNTVOFF_EL2 register.
> >  	 */
> > -	if (!has_vhe())
> > -		set_cntvoff(0);
> > +	set_cntvoff(0);
> >  }
> >  
> >  /*
> > @@ -550,7 +616,7 @@ static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu)
> >  	if (!kvm_timer_should_fire(vtimer)) {
> >  		kvm_timer_update_irq(vcpu, false, vtimer);
> >  		if (static_branch_likely(&has_gic_active_state))
> > -			set_vtimer_irq_phys_active(vcpu, false);
> > +			set_timer_irq_phys_active(vtimer, false);
> >  		else
> >  			enable_percpu_irq(host_vtimer_irq, host_vtimer_irq_flags);
> >  	}
> > @@ -625,7 +691,12 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
> >  	ptimer->hrtimer.function = kvm_phys_timer_expire;
> >  
> >  	vtimer->irq.irq = default_vtimer_irq.irq;
> > +	vtimer->host_timer_irq = host_vtimer_irq;
> > +	vtimer->host_timer_irq_flags = host_vtimer_irq_flags;
> > +
> >  	ptimer->irq.irq = default_ptimer_irq.irq;
> > +	ptimer->host_timer_irq = host_ptimer_irq;
> > +	ptimer->host_timer_irq_flags = host_ptimer_irq_flags;
> >  
> >  	vtimer->vcpu = vcpu;
> >  	ptimer->vcpu = vcpu;
> > @@ -634,6 +705,7 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
> >  static void kvm_timer_init_interrupt(void *info)
> >  {
> >  	enable_percpu_irq(host_vtimer_irq, host_vtimer_irq_flags);
> > +	enable_percpu_irq(host_ptimer_irq, host_ptimer_irq_flags);
> >  }
> >  
> >  int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value)
> > @@ -814,6 +886,8 @@ int kvm_timer_hyp_init(bool has_gic)
> >  		return -ENODEV;
> >  	}
> >  
> > +	/* First, do the virtual EL1 timer irq */
> > +
> >  	if (info->virtual_irq <= 0) {
> >  		kvm_err("kvm_arch_timer: invalid virtual timer IRQ: %d\n",
> >  			info->virtual_irq);
> > @@ -824,15 +898,15 @@ int kvm_timer_hyp_init(bool has_gic)
> >  	host_vtimer_irq_flags = irq_get_trigger_type(host_vtimer_irq);
> >  	if (host_vtimer_irq_flags != IRQF_TRIGGER_HIGH &&
> >  	    host_vtimer_irq_flags != IRQF_TRIGGER_LOW) {
> > -		kvm_err("Invalid trigger for IRQ%d, assuming level low\n",
> > +		kvm_err("Invalid trigger for vtimer IRQ%d, assuming level low\n",
> >  			host_vtimer_irq);
> >  		host_vtimer_irq_flags = IRQF_TRIGGER_LOW;
> >  	}
> >  
> >  	err = request_percpu_irq(host_vtimer_irq, kvm_arch_timer_handler,
> > -				 "kvm guest timer", kvm_get_running_vcpus());
> > +				 "kvm guest vtimer", kvm_get_running_vcpus());
> >  	if (err) {
> > -		kvm_err("kvm_arch_timer: can't request interrupt %d (%d)\n",
> > +		kvm_err("kvm_arch_timer: can't request vtimer interrupt %d (%d)\n",
> >  			host_vtimer_irq, err);
> >  		return err;
> >  	}
> > @@ -850,6 +924,38 @@ int kvm_timer_hyp_init(bool has_gic)
> >  
> >  	kvm_debug("virtual timer IRQ%d\n", host_vtimer_irq);
> >  
> > +	/* Now let's do the physical EL1 timer irq */
> > +
> > +	if (info->physical_irq > 0) {
> > +		host_ptimer_irq = info->physical_irq;
> > +		host_ptimer_irq_flags = irq_get_trigger_type(host_ptimer_irq);
> > +		if (host_ptimer_irq_flags != IRQF_TRIGGER_HIGH &&
> > +		    host_ptimer_irq_flags != IRQF_TRIGGER_LOW) {
> > +			kvm_err("Invalid trigger for ptimer IRQ%d, assuming level low\n",
> > +				host_ptimer_irq);
> > +			host_ptimer_irq_flags = IRQF_TRIGGER_LOW;
> > +		}
> > +
> > +		err = request_percpu_irq(host_ptimer_irq, kvm_arch_timer_handler,
> > +					 "kvm guest ptimer", kvm_get_running_vcpus());
> > +		if (err) {
> > +			kvm_err("kvm_arch_timer: can't request ptimer interrupt %d (%d)\n",
> > +				host_ptimer_irq, err);
> > +			return err;
> > +		}
> > +
> > +		if (has_gic) {
> > +			err = irq_set_vcpu_affinity(host_ptimer_irq,
> > +						    kvm_get_running_vcpus());
> > +			if (err) {
> > +				kvm_err("kvm_arch_timer: error setting vcpu affinity\n");
> > +				goto out_free_irq;
> > +			}
> > +		}
> > +
> > +		kvm_debug("physical timer IRQ%d\n", host_ptimer_irq);
> > +	}
> > +
> >  	cpuhp_setup_state(CPUHP_AP_KVM_ARM_TIMER_STARTING,
> >  			  "kvm/arm/timer:starting", kvm_timer_starting_cpu,
> >  			  kvm_timer_dying_cpu);
> > @@ -897,8 +1003,10 @@ bool kvm_arch_timer_get_input_level(int vintid)
> >  
> >  	if (vintid == vcpu_vtimer(vcpu)->irq.irq)
> >  		timer = vcpu_vtimer(vcpu);
> > +	else if (vintid == vcpu_ptimer(vcpu)->irq.irq)
> > +		timer = vcpu_ptimer(vcpu);
> >  	else
> > -		BUG(); /* We only map the vtimer so far */
> > +		BUG();
> >  
> >  	return kvm_timer_should_fire(timer);
> >  }
> > @@ -907,6 +1015,7 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
> >  {
> >  	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
> >  	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> > +	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
> >  	int ret;
> >  
> >  	if (timer->enabled)
> > @@ -929,6 +1038,13 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
> >  	if (ret)
> >  		return ret;
> >  
> > +	if (has_vhe()) {
> > +		ret = kvm_vgic_map_phys_irq(vcpu, host_ptimer_irq, ptimer->irq.irq,
> > +					    kvm_arch_timer_get_input_level);
> > +		if (ret)
> > +			return ret;
> > +	}
> > +
> >  no_vgic:
> >  	timer->enabled = 1;
> >  	return 0;
> > @@ -951,7 +1067,7 @@ void kvm_timer_init_vhe(void)
> >  	 * Physical counter access is allowed.
> >  	 */
> This trimmed comment and the comment for the function still state that physical
> timer access is trapped from the guest. I think both comments should be updated
> to reflect that that isn't the case anymore.
> >  	val = read_sysreg(cnthctl_el2);
> > -	val &= ~(CNTHCTL_EL1PCEN << cnthctl_shift);
> > +	val |= (CNTHCTL_EL1PCEN << cnthctl_shift);
> >  	val |= (CNTHCTL_EL1PCTEN << cnthctl_shift);
> >  	write_sysreg(val, cnthctl_el2);
> >  }

Yes, you're right.


Thanks,

    Christoffer

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 12/14] KVM: arm/arm64: arch_timer: Assign the phys timer on VHE systems
  2019-02-19 12:43     ` Christoffer Dall
@ 2019-02-20 17:58       ` Andre Przywara
  0 siblings, 0 replies; 33+ messages in thread
From: Andre Przywara @ 2019-02-20 17:58 UTC (permalink / raw)
  To: Christoffer Dall; +Cc: Marc Zyngier, kvmarm, linux-arm-kernel, kvm

On Tue, 19 Feb 2019 13:43:49 +0100
Christoffer Dall <christoffer.dall@arm.com> wrote:

> On Mon, Feb 18, 2019 at 03:10:49PM +0000, André Przywara wrote:
> > On Thu, 24 Jan 2019 15:00:30 +0100
> > Christoffer Dall <christoffer.dall@arm.com> wrote:
> > 
> > Hi,
> >   
> > > VHE systems don't have to emulate the physical timer, we can simply
> > > assigne the EL1 physical timer directly to the VM as the host always
> > > uses the EL2 timers.
> > > 
> > > In order to minimize the amount of cruft, AArch32 gets definitions for
> > > the physical timer too, but is should be generally unused on this
> > > architecture.
> > > 
> > > Co-written with Marc Zyngier <marc.zyngier@arm.com>
> > > 
> > > Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
> > > Signed-off-by: Christoffer Dall <christoffer.dall@arm.com>
> > > ---
> > >  arch/arm/include/asm/kvm_hyp.h |   4 +
> > >  include/kvm/arm_arch_timer.h   |   6 +
> > >  virt/kvm/arm/arch_timer.c      | 206 ++++++++++++++++++++++++++-------
> > >  3 files changed, 171 insertions(+), 45 deletions(-)
> > > 
> > > diff --git a/arch/arm/include/asm/kvm_hyp.h b/arch/arm/include/asm/kvm_hyp.h
> > > index e93a0cac9add..87bcd18df8d5 100644
> > > --- a/arch/arm/include/asm/kvm_hyp.h
> > > +++ b/arch/arm/include/asm/kvm_hyp.h
> > > @@ -40,6 +40,7 @@
> > >  #define TTBR1		__ACCESS_CP15_64(1, c2)
> > >  #define VTTBR		__ACCESS_CP15_64(6, c2)
> > >  #define PAR		__ACCESS_CP15_64(0, c7)
> > > +#define CNTP_CVAL	__ACCESS_CP15_64(2, c14)
> > >  #define CNTV_CVAL	__ACCESS_CP15_64(3, c14)
> > >  #define CNTVOFF		__ACCESS_CP15_64(4, c14)
> > >  
> > > @@ -85,6 +86,7 @@
> > >  #define TID_PRIV	__ACCESS_CP15(c13, 0, c0, 4)
> > >  #define HTPIDR		__ACCESS_CP15(c13, 4, c0, 2)
> > >  #define CNTKCTL		__ACCESS_CP15(c14, 0, c1, 0)
> > > +#define CNTP_CTL	__ACCESS_CP15(c14, 0, c2, 1)
> > >  #define CNTV_CTL	__ACCESS_CP15(c14, 0, c3, 1)
> > >  #define CNTHCTL		__ACCESS_CP15(c14, 4, c1, 0)
> > >  
> > > @@ -94,6 +96,8 @@
> > >  #define read_sysreg_el0(r)		read_sysreg(r##_el0)
> > >  #define write_sysreg_el0(v, r)		write_sysreg(v, r##_el0)
> > >  
> > > +#define cntp_ctl_el0			CNTP_CTL
> > > +#define cntp_cval_el0			CNTP_CVAL
> > >  #define cntv_ctl_el0			CNTV_CTL
> > >  #define cntv_cval_el0			CNTV_CVAL
> > >  #define cntvoff_el2			CNTVOFF
> > > diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
> > > index d40fe57a2d0d..722e0481f310 100644
> > > --- a/include/kvm/arm_arch_timer.h
> > > +++ b/include/kvm/arm_arch_timer.h
> > > @@ -50,6 +50,10 @@ struct arch_timer_context {
> > >  
> > >  	/* Emulated Timer (may be unused) */
> > >  	struct hrtimer			hrtimer;
> > > +
> > > +	/* Duplicated state from arch_timer.c for convenience */
> > > +	u32				host_timer_irq;
> > > +	u32				host_timer_irq_flags;
> > >  };
> > >  
> > >  enum loaded_timer_state {
> > > @@ -107,6 +111,8 @@ bool kvm_arch_timer_get_input_level(int vintid);
> > >  #define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.timers[TIMER_VTIMER])
> > >  #define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.timers[TIMER_PTIMER])
> > >  
> > > +#define arch_timer_ctx_index(ctx)	((ctx) - vcpu_timer((ctx)->vcpu)->timers)
> > > +
> > >  u64 kvm_arm_timer_read_sysreg(struct kvm_vcpu *vcpu,
> > >  			      enum kvm_arch_timers tmr,
> > >  			      enum kvm_arch_timer_regs treg);
> > > diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
> > > index 8b0eca5fbad1..eed8f48fbf9b 100644
> > > --- a/virt/kvm/arm/arch_timer.c
> > > +++ b/virt/kvm/arm/arch_timer.c
> > > @@ -35,7 +35,9 @@
> > >  
> > >  static struct timecounter *timecounter;
> > >  static unsigned int host_vtimer_irq;
> > > +static unsigned int host_ptimer_irq;
> > >  static u32 host_vtimer_irq_flags;
> > > +static u32 host_ptimer_irq_flags;
> > >  
> > >  static DEFINE_STATIC_KEY_FALSE(has_gic_active_state);
> > >  
> > > @@ -86,20 +88,24 @@ static void soft_timer_cancel(struct hrtimer *hrt)
> > >  static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
> > >  {
> > >  	struct kvm_vcpu *vcpu = *(struct kvm_vcpu **)dev_id;
> > > -	struct arch_timer_context *vtimer;
> > > +	struct arch_timer_context *ctx;
> > >  
> > >  	/*
> > >  	 * We may see a timer interrupt after vcpu_put() has been called which
> > >  	 * sets the CPU's vcpu pointer to NULL, because even though the timer
> > > -	 * has been disabled in vtimer_save_state(), the hardware interrupt
> > > +	 * has been disabled in timer_save_state(), the hardware interrupt
> > >  	 * signal may not have been retired from the interrupt controller yet.
> > >  	 */
> > >  	if (!vcpu)
> > >  		return IRQ_HANDLED;
> > >  
> > > -	vtimer = vcpu_vtimer(vcpu);
> > > -	if (kvm_timer_should_fire(vtimer))
> > > -		kvm_timer_update_irq(vcpu, true, vtimer);
> > > +	if (irq == host_vtimer_irq)
> > > +		ctx = vcpu_vtimer(vcpu);
> > > +	else
> > > +		ctx = vcpu_ptimer(vcpu);
> > > +
> > > +	if (kvm_timer_should_fire(ctx))
> > > +		kvm_timer_update_irq(vcpu, true, ctx);
> > >  
> > >  	if (userspace_irqchip(vcpu->kvm) &&
> > >  	    !static_branch_unlikely(&has_gic_active_state))
> > > @@ -208,13 +214,25 @@ static enum hrtimer_restart kvm_phys_timer_expire(struct hrtimer *hrt)
> > >  static bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx)
> > >  {
> > >  	struct arch_timer_cpu *timer = vcpu_timer(timer_ctx->vcpu);
> > > +	enum kvm_arch_timers index = arch_timer_ctx_index(timer_ctx);
> > >  	u64 cval, now;
> > >  
> > >  	if (timer->loaded == TIMER_EL1_LOADED) {
> > > -		u32 cnt_ctl;
> > > +		u32 cnt_ctl = 0;
> > > +
> > > +		switch (index) {
> > > +		case TIMER_VTIMER:
> > > +			cnt_ctl = read_sysreg_el0(cntv_ctl);
> > > +			break;
> > > +		case TIMER_PTIMER:
> > > +			cnt_ctl = read_sysreg_el0(cntp_ctl);
> > > +			break;
> > > +		case NR_KVM_TIMERS:
> > > +			/* GCC is braindead */
> > > +			cnt_ctl = 0;
> > > +			break;
> > > +		}
> > >  
> > > -		/* Only the virtual timer can be loaded so far */
> > > -		cnt_ctl = read_sysreg_el0(cntv_ctl);
> > >  		return  (cnt_ctl & ARCH_TIMER_CTRL_ENABLE) &&
> > >  		        (cnt_ctl & ARCH_TIMER_CTRL_IT_STAT) &&
> > >  		       !(cnt_ctl & ARCH_TIMER_CTRL_IT_MASK);
> > > @@ -310,7 +328,7 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
> > >  		return;
> > >  
> > >  	/*
> > > -	 * The vtimer virtual interrupt is a 'mapped' interrupt, meaning part
> > > +	 * If the timer virtual interrupt is a 'mapped' interrupt, part
> > >  	 * of its lifecycle is offloaded to the hardware, and we therefore may
> > >  	 * not have lowered the irq.level value before having to signal a new
> > >  	 * interrupt, but have to signal an interrupt every time the level is
> > > @@ -319,31 +337,55 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
> > >  	level = kvm_timer_should_fire(vtimer);
> > >  	kvm_timer_update_irq(vcpu, level, vtimer);
> > >  
> > > +	if (has_vhe()) {  
> > 
> > Not really critical, but wouldn't it be cleaner to use "if
> > (host_ptimer_irq > 0)" here to check if we map the phys timer as well?
> > This is at least how we originally derive the decision to initialise
> > everything in kvm_timer_hyp_init() below. Applies to the other instances
> > of "if (has_vhe())" as well.
> > But I guess we use has_vhe() because it's a static key? In this case
> > would it be worth to define some cosmetic wrapper, to improve readability?
> >   
> > > +		level = kvm_timer_should_fire(ptimer);
> > > +		kvm_timer_update_irq(vcpu, level, ptimer);
> > > +
> > > +		return;
> > > +	}
> > > +
> > >  	phys_timer_emulate(vcpu);
> > >  
> > >  	if (kvm_timer_should_fire(ptimer) != ptimer->irq.level)
> > >  		kvm_timer_update_irq(vcpu, !ptimer->irq.level, ptimer);
> > >  }
> > >  
> > > -static void vtimer_save_state(struct kvm_vcpu *vcpu)
> > > +static void timer_save_state(struct arch_timer_context *ctx)
> > >  {
> > > -	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
> > > -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> > > +	struct arch_timer_cpu *timer = vcpu_timer(ctx->vcpu);
> > > +	enum kvm_arch_timers index = arch_timer_ctx_index(ctx);
> > >  	unsigned long flags;
> > >  
> > > +	if (!timer->enabled)
> > > +		return;
> > > +
> > >  	local_irq_save(flags);
> > >  
> > >  	if (timer->loaded == TIMER_NOT_LOADED)
> > >  		goto out;
> > >  
> > > -	if (timer->enabled) {
> > > -		vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
> > > -		vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
> > > -	}
> > > +	switch (index) {
> > > +	case TIMER_VTIMER:
> > > +		ctx->cnt_ctl = read_sysreg_el0(cntv_ctl);
> > > +		ctx->cnt_cval = read_sysreg_el0(cntv_cval);
> > >  
> > > -	/* Disable the virtual timer */
> > > -	write_sysreg_el0(0, cntv_ctl);
> > > -	isb();
> > > +		/* Disable the timer */
> > > +		write_sysreg_el0(0, cntv_ctl);
> > > +		isb();
> > > +
> > > +		break;
> > > +	case TIMER_PTIMER:
> > > +		ctx->cnt_ctl = read_sysreg_el0(cntp_ctl);
> > > +		ctx->cnt_cval = read_sysreg_el0(cntp_cval);
> > > +
> > > +		/* Disable the timer */
> > > +		write_sysreg_el0(0, cntp_ctl);
> > > +		isb();
> > > +
> > > +		break;
> > > +	case NR_KVM_TIMERS:
> > > +		break; /* GCC is braindead */
> > > +	}
> > >  
> > >  	timer->loaded = TIMER_NOT_LOADED;
> > >  out:
> > > @@ -382,21 +424,33 @@ static void kvm_timer_unblocking(struct kvm_vcpu *vcpu)
> > >  	soft_timer_cancel(&timer->bg_timer);
> > >  }
> > >  
> > > -static void vtimer_restore_state(struct kvm_vcpu *vcpu)
> > > +static void timer_restore_state(struct arch_timer_context *ctx)
> > >  {
> > > -	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
> > > -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> > > +	struct arch_timer_cpu *timer = vcpu_timer(ctx->vcpu);
> > > +	enum kvm_arch_timers index = arch_timer_ctx_index(ctx);
> > >  	unsigned long flags;
> > >  
> > > +	if (!timer->enabled)
> > > +		return;
> > > +
> > >  	local_irq_save(flags);
> > >  
> > >  	if (timer->loaded == TIMER_EL1_LOADED)
> > >  		goto out;
> > >  
> > > -	if (timer->enabled) {
> > > -		write_sysreg_el0(vtimer->cnt_cval, cntv_cval);
> > > +	switch (index) {
> > > +	case TIMER_VTIMER:
> > > +		write_sysreg_el0(ctx->cnt_cval, cntv_cval);
> > > +		isb();
> > > +		write_sysreg_el0(ctx->cnt_ctl, cntv_ctl);
> > > +		break;
> > > +	case TIMER_PTIMER:
> > > +		write_sysreg_el0(ctx->cnt_cval, cntp_cval);
> > >  		isb();
> > > -		write_sysreg_el0(vtimer->cnt_ctl, cntv_ctl);
> > > +		write_sysreg_el0(ctx->cnt_ctl, cntp_ctl);
> > > +		break;
> > > +	case NR_KVM_TIMERS:
> > > +		break; /* GCC is braindead */
> > >  	}
> > >  
> > >  	timer->loaded = TIMER_EL1_LOADED;
> > > @@ -419,23 +473,23 @@ static void set_cntvoff(u64 cntvoff)
> > >  	kvm_call_hyp(__kvm_timer_set_cntvoff, low, high);
> > >  }
> > >  
> > > -static inline void set_vtimer_irq_phys_active(struct kvm_vcpu *vcpu, bool active)
> > > +static inline void set_timer_irq_phys_active(struct arch_timer_context *ctx, bool active)
> > >  {
> > >  	int r;
> > > -	r = irq_set_irqchip_state(host_vtimer_irq, IRQCHIP_STATE_ACTIVE, active);
> > > +	r = irq_set_irqchip_state(ctx->host_timer_irq, IRQCHIP_STATE_ACTIVE, active);
> > >  	WARN_ON(r);
> > >  }
> > >  
> > > -static void kvm_timer_vcpu_load_gic(struct kvm_vcpu *vcpu)
> > > +static void kvm_timer_vcpu_load_gic(struct arch_timer_context *ctx)
> > >  {
> > > -	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> > > +	struct kvm_vcpu *vcpu = ctx->vcpu;
> > >  	bool phys_active;
> > >  
> > >  	if (irqchip_in_kernel(vcpu->kvm))
> > > -		phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
> > > +		phys_active = kvm_vgic_map_is_active(vcpu, ctx->irq.irq);
> > >  	else
> > > -		phys_active = vtimer->irq.level;
> > > -	set_vtimer_irq_phys_active(vcpu, phys_active);
> > > +		phys_active = ctx->irq.level;
> > > +	set_timer_irq_phys_active(ctx, phys_active);
> > >  }
> > >  
> > >  static void kvm_timer_vcpu_load_nogic(struct kvm_vcpu *vcpu)
> > > @@ -467,14 +521,22 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
> > >  	if (unlikely(!timer->enabled))
> > >  		return;
> > >  
> > > -	if (static_branch_likely(&has_gic_active_state))
> > > -		kvm_timer_vcpu_load_gic(vcpu);
> > > -	else
> > > +	if (static_branch_likely(&has_gic_active_state)) {
> > > +		kvm_timer_vcpu_load_gic(vtimer);
> > > +		if (has_vhe())
> > > +			kvm_timer_vcpu_load_gic(ptimer);
> > > +	} else {
> > >  		kvm_timer_vcpu_load_nogic(vcpu);
> > > +	}
> > >  
> > >  	set_cntvoff(vtimer->cntvoff);
> > >  
> > > -	vtimer_restore_state(vcpu);
> > > +	timer_restore_state(vtimer);
> > > +
> > > +	if (has_vhe()) {
> > > +		timer_restore_state(ptimer);
> > > +		return;
> > > +	}
> > >  
> > >  	/* Set the background timer for the physical timer emulation. */
> > >  	phys_timer_emulate(vcpu);
> > > @@ -506,12 +568,17 @@ bool kvm_timer_should_notify_user(struct kvm_vcpu *vcpu)
> > >  void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
> > >  {
> > >  	struct arch_timer_cpu *timer = vcpu_timer(vcpu);
> > > +	struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
> > >  	struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
> > >  
> > >  	if (unlikely(!timer->enabled))
> > >  		return;
> > >  
> > > -	vtimer_save_state(vcpu);
> > > +	timer_save_state(vtimer);
> > > +	if (has_vhe()) {
> > > +		timer_save_state(ptimer);
> > > +		return;
> > > +	}
> > >  
> > >  	/*
> > >  	 * Cancel the physical timer emulation, because the only case where we
> > > @@ -534,8 +601,7 @@ void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu)
> > >  	 * counter of non-VHE case. For VHE, the virtual counter uses a fixed
> > >  	 * virtual offset of zero, so no need to zero CNTVOFF_EL2 register.
> > >  	 */
> > > -	if (!has_vhe())
> > > -		set_cntvoff(0);
> > > +	set_cntvoff(0);
> > >  }
> > >  
> > >  /*
> > > @@ -550,7 +616,7 @@ static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu)
> > >  	if (!kvm_timer_should_fire(vtimer)) {
> > >  		kvm_timer_update_irq(vcpu, false, vtimer);
> > >  		if (static_branch_likely(&has_gic_active_state))
> > > -			set_vtimer_irq_phys_active(vcpu, false);
> > > +			set_timer_irq_phys_active(vtimer, false);
> > >  		else
> > >  			enable_percpu_irq(host_vtimer_irq, host_vtimer_irq_flags);
> > >  	}
> > > @@ -625,7 +691,12 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
> > >  	ptimer->hrtimer.function = kvm_phys_timer_expire;
> > >  
> > >  	vtimer->irq.irq = default_vtimer_irq.irq;
> > > +	vtimer->host_timer_irq = host_vtimer_irq;
> > > +	vtimer->host_timer_irq_flags = host_vtimer_irq_flags;
> > > +
> > >  	ptimer->irq.irq = default_ptimer_irq.irq;
> > > +	ptimer->host_timer_irq = host_ptimer_irq;
> > > +	ptimer->host_timer_irq_flags = host_ptimer_irq_flags;
> > >  
> > >  	vtimer->vcpu = vcpu;
> > >  	ptimer->vcpu = vcpu;
> > > @@ -634,6 +705,7 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
> > >  static void kvm_timer_init_interrupt(void *info)
> > >  {
> > >  	enable_percpu_irq(host_vtimer_irq, host_vtimer_irq_flags);
> > > +	enable_percpu_irq(host_ptimer_irq, host_ptimer_irq_flags);  
> > 
> > Shouldn't we only enable host_ptimer_irq() if we actually pass this on
> > here? So either guarded by has_vhe() or (host_ptimer_irq > 0)?
> > Otherwise we would enable IRQ 0?
> >   
> 
> I think the right fix is to raise an error if a VHE system doesn't give
> us a valid physical irq number during init, and then leave the checks
> for has_vhe() here.

That sounds like a good compromise to me. I just want to avoid the casual
reader to be puzzled about the dependency between "phys timer passed on"
and VHE. Comments would probably do as well.

Thanks!
Andre.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 06/14] KVM: arm/arm64: Factor out VMID into struct kvm_vmid
  2019-01-24 14:00 ` [PATCH 06/14] KVM: arm/arm64: Factor out VMID into struct kvm_vmid Christoffer Dall
  2019-01-24 19:01   ` James Morse
  2019-01-25 11:05   ` Julien Thierry
@ 2019-02-21 11:02   ` Julien Grall
  2019-02-22  9:18     ` Marc Zyngier
  2 siblings, 1 reply; 33+ messages in thread
From: Julien Grall @ 2019-02-21 11:02 UTC (permalink / raw)
  To: Christoffer Dall, kvmarm, linux-arm-kernel; +Cc: Marc Zyngier, nd, kvm

Hi Christoffer,

On 24/01/2019 14:00, Christoffer Dall wrote:
> Note that to avoid mapping the kvm_vmid_bits variable into hyp, we
> simply forego the masking of the vmid value in kvm_get_vttbr and rely on
> update_vmid to always assign a valid vmid value (within the supported
> range).

[...]

> -	kvm->arch.vmid = kvm_next_vmid;
> +	vmid->vmid = kvm_next_vmid;
>   	kvm_next_vmid++;
> -	kvm_next_vmid &= (1 << kvm_vmid_bits) - 1;
> -
> -	/* update vttbr to be used with the new vmid */
> -	pgd_phys = virt_to_phys(kvm->arch.pgd);
> -	BUG_ON(pgd_phys & ~kvm_vttbr_baddr_mask(kvm));
> -	vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & VTTBR_VMID_MASK(kvm_vmid_bits);
> -	kvm->arch.vttbr = kvm_phys_to_vttbr(pgd_phys) | vmid | cnp;
> +	kvm_next_vmid &= (1 << kvm_get_vmid_bits()) - 1;

The arm64 version of kvm_get_vmid_bits does not look cheap. Indeed it required 
to read the sanitized value of SYS_ID_AA64MMFR1_EL1 that is implemented using 
the function bsearch.

So wouldn't it be better to keep kvm_vmid_bits variable for use in update_vttbr()?

Cheers,

-- 
Julien Grall
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 06/14] KVM: arm/arm64: Factor out VMID into struct kvm_vmid
  2019-02-21 11:02   ` Julien Grall
@ 2019-02-22  9:18     ` Marc Zyngier
  2019-02-22 11:42       ` Julien Grall
  0 siblings, 1 reply; 33+ messages in thread
From: Marc Zyngier @ 2019-02-22  9:18 UTC (permalink / raw)
  To: Julien Grall; +Cc: kvm, nd, Christoffer Dall, linux-arm-kernel, kvmarm

On Thu, 21 Feb 2019 11:02:56 +0000
Julien Grall <Julien.Grall@arm.com> wrote:

Hi Julien,

> Hi Christoffer,
> 
> On 24/01/2019 14:00, Christoffer Dall wrote:
> > Note that to avoid mapping the kvm_vmid_bits variable into hyp, we
> > simply forego the masking of the vmid value in kvm_get_vttbr and rely on
> > update_vmid to always assign a valid vmid value (within the supported
> > range).  
> 
> [...]
> 
> > -	kvm->arch.vmid = kvm_next_vmid;
> > +	vmid->vmid = kvm_next_vmid;
> >   	kvm_next_vmid++;
> > -	kvm_next_vmid &= (1 << kvm_vmid_bits) - 1;
> > -
> > -	/* update vttbr to be used with the new vmid */
> > -	pgd_phys = virt_to_phys(kvm->arch.pgd);
> > -	BUG_ON(pgd_phys & ~kvm_vttbr_baddr_mask(kvm));
> > -	vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & VTTBR_VMID_MASK(kvm_vmid_bits);
> > -	kvm->arch.vttbr = kvm_phys_to_vttbr(pgd_phys) | vmid | cnp;
> > +	kvm_next_vmid &= (1 << kvm_get_vmid_bits()) - 1;  
> 
> The arm64 version of kvm_get_vmid_bits does not look cheap. Indeed it required 
> to read the sanitized value of SYS_ID_AA64MMFR1_EL1 that is implemented using 
> the function bsearch.
> 
> So wouldn't it be better to keep kvm_vmid_bits variable for use in update_vttbr()?

How often does this happen? Can you measure this overhead at all?

My understanding is that we hit this path on rollover only, having IPIed
all CPUs and invalidated all TLBs. I seriously doubt you can observe
any sort of overhead at all, given that it is so incredibly rare. But
feel free to prove me wrong!

Thanks,

	M.
-- 
Without deviation from the norm, progress is not possible.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 06/14] KVM: arm/arm64: Factor out VMID into struct kvm_vmid
  2019-02-22  9:18     ` Marc Zyngier
@ 2019-02-22 11:42       ` Julien Grall
  2019-02-22 12:14         ` Marc Zyngier
  0 siblings, 1 reply; 33+ messages in thread
From: Julien Grall @ 2019-02-22 11:42 UTC (permalink / raw)
  To: Marc Zyngier; +Cc: kvm, nd, Christoffer Dall, linux-arm-kernel, kvmarm

Hi Marc,

On 22/02/2019 09:18, Marc Zyngier wrote:
> On Thu, 21 Feb 2019 11:02:56 +0000
> Julien Grall <Julien.Grall@arm.com> wrote:
> 
> Hi Julien,
> 
>> Hi Christoffer,
>>
>> On 24/01/2019 14:00, Christoffer Dall wrote:
>>> Note that to avoid mapping the kvm_vmid_bits variable into hyp, we
>>> simply forego the masking of the vmid value in kvm_get_vttbr and rely on
>>> update_vmid to always assign a valid vmid value (within the supported
>>> range).
>>
>> [...]
>>
>>> -	kvm->arch.vmid = kvm_next_vmid;
>>> +	vmid->vmid = kvm_next_vmid;
>>>    	kvm_next_vmid++;
>>> -	kvm_next_vmid &= (1 << kvm_vmid_bits) - 1;
>>> -
>>> -	/* update vttbr to be used with the new vmid */
>>> -	pgd_phys = virt_to_phys(kvm->arch.pgd);
>>> -	BUG_ON(pgd_phys & ~kvm_vttbr_baddr_mask(kvm));
>>> -	vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & VTTBR_VMID_MASK(kvm_vmid_bits);
>>> -	kvm->arch.vttbr = kvm_phys_to_vttbr(pgd_phys) | vmid | cnp;
>>> +	kvm_next_vmid &= (1 << kvm_get_vmid_bits()) - 1;
>>
>> The arm64 version of kvm_get_vmid_bits does not look cheap. Indeed it required
>> to read the sanitized value of SYS_ID_AA64MMFR1_EL1 that is implemented using
>> the function bsearch.
>>
>> So wouldn't it be better to keep kvm_vmid_bits variable for use in update_vttbr()?
> 
> How often does this happen? Can you measure this overhead at all?
> 
> My understanding is that we hit this path on rollover only, having IPIed
> all CPUs and invalidated all TLBs. I seriously doubt you can observe
> any sort of overhead at all, given that it is so incredibly rare. But
> feel free to prove me wrong!

That would happen on roll-over and the first time you allocate VMID for the VM.

I am planning to run some test with 3-bit VMIDs and provide them next week.

Cheers,

-- 
Julien Grall

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 06/14] KVM: arm/arm64: Factor out VMID into struct kvm_vmid
  2019-02-22 11:42       ` Julien Grall
@ 2019-02-22 12:14         ` Marc Zyngier
  0 siblings, 0 replies; 33+ messages in thread
From: Marc Zyngier @ 2019-02-22 12:14 UTC (permalink / raw)
  To: Julien Grall; +Cc: kvm, nd, Christoffer Dall, linux-arm-kernel, kvmarm

On Fri, 22 Feb 2019 11:42:46 +0000
Julien Grall <julien.grall@arm.com> wrote:

> Hi Marc,
> 
> On 22/02/2019 09:18, Marc Zyngier wrote:
> > On Thu, 21 Feb 2019 11:02:56 +0000
> > Julien Grall <Julien.Grall@arm.com> wrote:
> > 
> > Hi Julien,
> >   
> >> Hi Christoffer,
> >>
> >> On 24/01/2019 14:00, Christoffer Dall wrote:  
> >>> Note that to avoid mapping the kvm_vmid_bits variable into hyp, we
> >>> simply forego the masking of the vmid value in kvm_get_vttbr and rely on
> >>> update_vmid to always assign a valid vmid value (within the supported
> >>> range).  
> >>
> >> [...]
> >>  
> >>> -	kvm->arch.vmid = kvm_next_vmid;
> >>> +	vmid->vmid = kvm_next_vmid;
> >>>    	kvm_next_vmid++;
> >>> -	kvm_next_vmid &= (1 << kvm_vmid_bits) - 1;
> >>> -
> >>> -	/* update vttbr to be used with the new vmid */
> >>> -	pgd_phys = virt_to_phys(kvm->arch.pgd);
> >>> -	BUG_ON(pgd_phys & ~kvm_vttbr_baddr_mask(kvm));
> >>> -	vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & VTTBR_VMID_MASK(kvm_vmid_bits);
> >>> -	kvm->arch.vttbr = kvm_phys_to_vttbr(pgd_phys) | vmid | cnp;
> >>> +	kvm_next_vmid &= (1 << kvm_get_vmid_bits()) - 1;  
> >>
> >> The arm64 version of kvm_get_vmid_bits does not look cheap. Indeed it required
> >> to read the sanitized value of SYS_ID_AA64MMFR1_EL1 that is implemented using
> >> the function bsearch.
> >>
> >> So wouldn't it be better to keep kvm_vmid_bits variable for use in update_vttbr()?  
> > 
> > How often does this happen? Can you measure this overhead at all?
> > 
> > My understanding is that we hit this path on rollover only, having IPIed
> > all CPUs and invalidated all TLBs. I seriously doubt you can observe
> > any sort of overhead at all, given that it is so incredibly rare. But
> > feel free to prove me wrong!  
> 
> That would happen on roll-over and the first time you allocate VMID for the VM.
> 
> I am planning to run some test with 3-bit VMIDs and provide them next week.

Sure, but who implements 3 bit VMIDs? I'm only interested in
performance on real HW, and the minimal implementation allowed is
8bits.

So don't bother testing this with such contrived conditions. Test it
for real, on a system that can run enough stuff concurrently to quickly
exhaust its VMID space and provoke rollovers.

Alternatively, measure the time it takes to create a single VM that
exits immediately. On its own, that'd be a useful unit test for
extremely short-lived VMs.

Thanks,

	M.
-- 
Without deviation from the norm, progress is not possible.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

end of thread, other threads:[~2019-02-22 12:14 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-24 14:00 [PATCH 00/14] KVM: arm/arm64: Various rework in preparation of nested virt support Christoffer Dall
2019-01-24 14:00 ` [PATCH 01/14] arm/arm64: KVM: Introduce kvm_call_hyp_ret() Christoffer Dall
2019-01-24 14:00 ` [PATCH 02/14] arm64: KVM: Allow for direct call of HYP functions when using VHE Christoffer Dall
2019-01-24 14:00 ` [PATCH 03/14] arm64: KVM: Drop VHE-specific HYP call stub Christoffer Dall
2019-01-24 14:00 ` [PATCH 04/14] ARM: KVM: Teach some form of type-safety to kvm_call_hyp Christoffer Dall
2019-01-24 14:00 ` [PATCH 05/14] arm/arm64: KVM: Statically configure the host's view of MPIDR Christoffer Dall
2019-01-24 14:00 ` [PATCH 06/14] KVM: arm/arm64: Factor out VMID into struct kvm_vmid Christoffer Dall
2019-01-24 19:01   ` James Morse
2019-01-25 10:09     ` Marc Zyngier
2019-01-25 11:05   ` Julien Thierry
2019-01-31 13:01     ` Marc Zyngier
2019-02-21 11:02   ` Julien Grall
2019-02-22  9:18     ` Marc Zyngier
2019-02-22 11:42       ` Julien Grall
2019-02-22 12:14         ` Marc Zyngier
2019-01-24 14:00 ` [PATCH 07/14] KVM: arm/arm64: Simplify bg_timer programming Christoffer Dall
2019-01-24 14:00 ` [PATCH 08/14] KVM: arm64: Fix ICH_ELRSR_EL2 sysreg naming Christoffer Dall
2019-01-24 14:00 ` [PATCH 09/14] KVM: arm64: Reuse sys_reg() macro when searching the trap table Christoffer Dall
2019-01-30  8:57   ` André Przywara
2019-01-24 14:00 ` [PATCH 10/14] KVM: arm/arm64: consolidate arch timer trap handlers Christoffer Dall
2019-01-25 12:33   ` Julien Thierry
2019-01-30 17:38     ` Marc Zyngier
2019-01-24 14:00 ` [PATCH 11/14] KVM: arm/arm64: timer: Rework data structures for multiple timers Christoffer Dall
2019-02-18 15:10   ` André Przywara
2019-02-19 12:27     ` Christoffer Dall
2019-01-24 14:00 ` [PATCH 12/14] KVM: arm/arm64: arch_timer: Assign the phys timer on VHE systems Christoffer Dall
2019-02-18 15:10   ` André Przywara
2019-02-19 12:43     ` Christoffer Dall
2019-02-20 17:58       ` Andre Przywara
2019-02-19 11:39   ` Alexandru Elisei
2019-02-19 13:03     ` Christoffer Dall
2019-01-24 14:00 ` [PATCH 13/14] KVM: arm/arm64: Rework the timer code to use a timer_map Christoffer Dall
2019-01-24 14:00 ` [PATCH 14/14] KVM: arm/arm64: Move kvm_is_write_fault to header file Christoffer Dall

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).