From: Oliver Upton <oupton@google.com>
To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu
Cc: Catalin Marinas <catalin.marinas@arm.com>,
Will Deacon <will@kernel.org>, Marc Zyngier <maz@kernel.org>,
Peter Shier <pshier@google.com>,
Sean Christopherson <seanjc@google.com>,
David Matlack <dmatlack@google.com>,
Paolo Bonzini <pbonzini@redhat.com>,
linux-arm-kernel@lists.infradead.org,
Jim Mattson <jmattson@google.com>
Subject: [PATCH v8 8/8] KVM: arm64: Emulate physical counter offsetting on non-ECV systems
Date: Thu, 16 Sep 2021 18:15:10 +0000 [thread overview]
Message-ID: <20210916181510.963449-9-oupton@google.com> (raw)
In-Reply-To: <20210916181510.963449-1-oupton@google.com>
Unfortunately, ECV hasn't yet arrived in any tangible hardware. At the
same time, controlling the guest view of the physical counter-timer is
useful. Support guest counter-timer offsetting on non-ECV systems by
trapping guest accesses to the physical counter-timer. Emulate reads of
the physical counter in the fast exit path.
Signed-off-by: Oliver Upton <oupton@google.com>
Reviewed-by: Andrew Jones <drjones@redhat.com>
---
arch/arm64/include/asm/sysreg.h | 2 ++
arch/arm64/kvm/arch_timer.c | 47 +++++++++++++------------
arch/arm64/kvm/hyp/include/hyp/switch.h | 32 +++++++++++++++++
arch/arm64/kvm/hyp/nvhe/timer-sr.c | 11 ++++--
include/kvm/arm_arch_timer.h | 3 ++
5 files changed, 71 insertions(+), 24 deletions(-)
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index d5a686dff57e..cb9f72ebd6ec 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -506,6 +506,8 @@
#define SYS_AMEVCNTR0_MEM_STALL SYS_AMEVCNTR0_EL0(3)
#define SYS_CNTFRQ_EL0 sys_reg(3, 3, 14, 0, 0)
+#define SYS_CNTPCT_EL0 sys_reg(3, 3, 14, 0, 1)
+#define SYS_CNTPCTSS_EL0 sys_reg(3, 3, 14, 0, 5)
#define SYS_CNTP_TVAL_EL0 sys_reg(3, 3, 14, 2, 0)
#define SYS_CNTP_CTL_EL0 sys_reg(3, 3, 14, 2, 1)
diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index 68fb5ddb9e7a..2280a99ab98b 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -51,7 +51,7 @@ static void kvm_arm_timer_write(struct kvm_vcpu *vcpu,
static u64 kvm_arm_timer_read(struct kvm_vcpu *vcpu,
struct arch_timer_context *timer,
enum kvm_arch_timer_regs treg);
-static void kvm_timer_enable_traps_vhe(void);
+static void kvm_timer_enable_traps_vhe(struct kvm_vcpu *vcpu);
u32 timer_get_ctl(struct arch_timer_context *ctxt)
{
@@ -179,8 +179,13 @@ 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;
+ if (!ptimer_emulation_required(vcpu)) {
+ map->direct_ptimer = vcpu_ptimer(vcpu);
+ map->emul_ptimer = NULL;
+ } else {
+ map->direct_ptimer = NULL;
+ map->emul_ptimer = vcpu_ptimer(vcpu);
+ }
} else {
map->direct_vtimer = vcpu_vtimer(vcpu);
map->direct_ptimer = NULL;
@@ -666,7 +671,7 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
timer_emulate(map.emul_ptimer);
if (has_vhe())
- kvm_timer_enable_traps_vhe();
+ kvm_timer_enable_traps_vhe(vcpu);
}
bool kvm_timer_should_notify_user(struct kvm_vcpu *vcpu)
@@ -1364,22 +1369,29 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
* The host kernel runs at EL2 with HCR_EL2.TGE == 1,
* and this makes those bits have no effect for the host kernel execution.
*/
-static void kvm_timer_enable_traps_vhe(void)
+static void kvm_timer_enable_traps_vhe(struct kvm_vcpu *vcpu)
{
/* When HCR_EL2.E2H ==1, EL1PCEN and EL1PCTEN are shifted by 10 */
u32 cnthctl_shift = 10;
- u64 val;
+ u64 val, mask;
+
+ mask = CNTHCTL_EL1PCEN << cnthctl_shift;
+ mask |= CNTHCTL_EL1PCTEN << cnthctl_shift;
- /*
- * VHE systems allow the guest direct access to the EL1 physical
- * timer/counter.
- */
val = read_sysreg(cnthctl_el2);
- val |= (CNTHCTL_EL1PCEN << cnthctl_shift);
- val |= (CNTHCTL_EL1PCTEN << cnthctl_shift);
if (cpus_have_final_cap(ARM64_HAS_ECV2))
val |= CNTHCTL_ECV;
+
+ /*
+ * VHE systems allow the guest direct access to the EL1 physical
+ * timer/counter if offsetting isn't requested on a non-ECV system.
+ */
+ if (ptimer_emulation_required(vcpu))
+ val &= ~mask;
+ else
+ val |= mask;
+
write_sysreg(val, cnthctl_el2);
}
@@ -1434,9 +1446,6 @@ static int kvm_arm_timer_set_attr_offset(struct kvm_vcpu *vcpu,
u64 __user *uaddr = (u64 __user *)(long)attr->addr;
u64 offset;
- if (!kvm_timer_physical_offset_allowed())
- return -ENXIO;
-
if (get_user(offset, uaddr))
return -EFAULT;
@@ -1485,9 +1494,6 @@ static int kvm_arm_timer_get_attr_offset(struct kvm_vcpu *vcpu,
u64 __user *uaddr = (u64 __user *)(long)attr->addr;
u64 offset;
- if (!kvm_timer_physical_offset_allowed())
- return -ENXIO;
-
offset = timer_get_offset(vcpu_ptimer(vcpu));
return put_user(offset, uaddr);
}
@@ -1511,11 +1517,8 @@ int kvm_arm_timer_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
switch (attr->attr) {
case KVM_ARM_VCPU_TIMER_IRQ_VTIMER:
case KVM_ARM_VCPU_TIMER_IRQ_PTIMER:
- return 0;
case KVM_ARM_VCPU_TIMER_PHYS_OFFSET:
- if (kvm_timer_physical_offset_allowed())
- return 0;
- break;
+ return 0;
}
return -ENXIO;
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index a0e78a6027be..9c42a299957c 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -15,6 +15,7 @@
#include <linux/jump_label.h>
#include <uapi/linux/psci.h>
+#include <kvm/arm_arch_timer.h>
#include <kvm/arm_psci.h>
#include <asm/barrier.h>
@@ -409,6 +410,34 @@ static inline bool __hyp_handle_ptrauth(struct kvm_vcpu *vcpu)
return true;
}
+static inline u64 __timer_read_cntpct(struct kvm_vcpu *vcpu)
+{
+ return __arch_counter_get_cntpct() - vcpu_ptimer(vcpu)->host_offset;
+}
+
+static inline bool __hyp_handle_counter(struct kvm_vcpu *vcpu)
+{
+ u32 sysreg;
+ int rt;
+ u64 rv;
+
+ if (kvm_timer_physical_offset_allowed())
+ return false;
+
+ if (kvm_vcpu_trap_get_class(vcpu) != ESR_ELx_EC_SYS64)
+ return false;
+
+ sysreg = esr_sys64_to_sysreg(kvm_vcpu_get_esr(vcpu));
+ if (sysreg != SYS_CNTPCT_EL0 && sysreg != SYS_CNTPCTSS_EL0)
+ return false;
+
+ rt = kvm_vcpu_sys_get_rt(vcpu);
+ rv = __timer_read_cntpct(vcpu);
+ vcpu_set_reg(vcpu, rt, rv);
+ __kvm_skip_instr(vcpu);
+ return true;
+}
+
/*
* Return true when we were able to fixup the guest exit and should return to
* the guest, false when we should restore the host state and return to the
@@ -443,6 +472,9 @@ static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
if (*exit_code != ARM_EXCEPTION_TRAP)
goto exit;
+ if (__hyp_handle_counter(vcpu))
+ goto guest;
+
if (cpus_have_final_cap(ARM64_WORKAROUND_CAVIUM_TX2_219_TVM) &&
kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_SYS64 &&
handle_tx2_tvm(vcpu))
diff --git a/arch/arm64/kvm/hyp/nvhe/timer-sr.c b/arch/arm64/kvm/hyp/nvhe/timer-sr.c
index 9072e71693ba..6c0834421eae 100644
--- a/arch/arm64/kvm/hyp/nvhe/timer-sr.c
+++ b/arch/arm64/kvm/hyp/nvhe/timer-sr.c
@@ -39,10 +39,17 @@ void __timer_enable_traps(struct kvm_vcpu *vcpu)
/*
* Disallow physical timer access for the guest
- * Physical counter access is allowed
*/
val = read_sysreg(cnthctl_el2);
val &= ~CNTHCTL_EL1PCEN;
- val |= CNTHCTL_EL1PCTEN;
+
+ /*
+ * Disallow physical counter access for the guest if offsetting is
+ * requested on a non-ECV system.
+ */
+ if (ptimer_emulation_required(vcpu))
+ val &= ~CNTHCTL_EL1PCTEN;
+ else
+ val |= CNTHCTL_EL1PCTEN;
write_sysreg(val, cnthctl_el2);
}
diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index d06294aa356e..252c012db505 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -96,6 +96,9 @@ bool kvm_arch_timer_get_input_level(int vintid);
#define arch_timer_ctx_index(ctx) ((ctx) - vcpu_timer((ctx)->vcpu)->timers)
+#define ptimer_emulation_required(v) \
+ (!cpus_have_final_cap(ARM64_HAS_ECV2) && vcpu_ptimer(v)->host_offset)
+
u64 kvm_arm_timer_read_sysreg(struct kvm_vcpu *vcpu,
enum kvm_arch_timers tmr,
enum kvm_arch_timer_regs treg);
--
2.33.0.309.g3052b89438-goog
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
WARNING: multiple messages have this Message-ID (diff)
From: Oliver Upton <oupton@google.com>
To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu
Cc: Paolo Bonzini <pbonzini@redhat.com>,
Sean Christopherson <seanjc@google.com>,
Marc Zyngier <maz@kernel.org>, Peter Shier <pshier@google.com>,
Jim Mattson <jmattson@google.com>,
David Matlack <dmatlack@google.com>,
Ricardo Koller <ricarkol@google.com>,
Jing Zhang <jingzhangos@google.com>,
Raghavendra Rao Anata <rananta@google.com>,
James Morse <james.morse@arm.com>,
Alexandru Elisei <alexandru.elisei@arm.com>,
Suzuki K Poulose <suzuki.poulose@arm.com>,
linux-arm-kernel@lists.infradead.org,
Andrew Jones <drjones@redhat.com>, Will Deacon <will@kernel.org>,
Catalin Marinas <catalin.marinas@arm.com>,
Oliver Upton <oupton@google.com>
Subject: [PATCH v8 8/8] KVM: arm64: Emulate physical counter offsetting on non-ECV systems
Date: Thu, 16 Sep 2021 18:15:10 +0000 [thread overview]
Message-ID: <20210916181510.963449-9-oupton@google.com> (raw)
In-Reply-To: <20210916181510.963449-1-oupton@google.com>
Unfortunately, ECV hasn't yet arrived in any tangible hardware. At the
same time, controlling the guest view of the physical counter-timer is
useful. Support guest counter-timer offsetting on non-ECV systems by
trapping guest accesses to the physical counter-timer. Emulate reads of
the physical counter in the fast exit path.
Signed-off-by: Oliver Upton <oupton@google.com>
Reviewed-by: Andrew Jones <drjones@redhat.com>
---
arch/arm64/include/asm/sysreg.h | 2 ++
arch/arm64/kvm/arch_timer.c | 47 +++++++++++++------------
arch/arm64/kvm/hyp/include/hyp/switch.h | 32 +++++++++++++++++
arch/arm64/kvm/hyp/nvhe/timer-sr.c | 11 ++++--
include/kvm/arm_arch_timer.h | 3 ++
5 files changed, 71 insertions(+), 24 deletions(-)
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index d5a686dff57e..cb9f72ebd6ec 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -506,6 +506,8 @@
#define SYS_AMEVCNTR0_MEM_STALL SYS_AMEVCNTR0_EL0(3)
#define SYS_CNTFRQ_EL0 sys_reg(3, 3, 14, 0, 0)
+#define SYS_CNTPCT_EL0 sys_reg(3, 3, 14, 0, 1)
+#define SYS_CNTPCTSS_EL0 sys_reg(3, 3, 14, 0, 5)
#define SYS_CNTP_TVAL_EL0 sys_reg(3, 3, 14, 2, 0)
#define SYS_CNTP_CTL_EL0 sys_reg(3, 3, 14, 2, 1)
diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index 68fb5ddb9e7a..2280a99ab98b 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -51,7 +51,7 @@ static void kvm_arm_timer_write(struct kvm_vcpu *vcpu,
static u64 kvm_arm_timer_read(struct kvm_vcpu *vcpu,
struct arch_timer_context *timer,
enum kvm_arch_timer_regs treg);
-static void kvm_timer_enable_traps_vhe(void);
+static void kvm_timer_enable_traps_vhe(struct kvm_vcpu *vcpu);
u32 timer_get_ctl(struct arch_timer_context *ctxt)
{
@@ -179,8 +179,13 @@ 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;
+ if (!ptimer_emulation_required(vcpu)) {
+ map->direct_ptimer = vcpu_ptimer(vcpu);
+ map->emul_ptimer = NULL;
+ } else {
+ map->direct_ptimer = NULL;
+ map->emul_ptimer = vcpu_ptimer(vcpu);
+ }
} else {
map->direct_vtimer = vcpu_vtimer(vcpu);
map->direct_ptimer = NULL;
@@ -666,7 +671,7 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
timer_emulate(map.emul_ptimer);
if (has_vhe())
- kvm_timer_enable_traps_vhe();
+ kvm_timer_enable_traps_vhe(vcpu);
}
bool kvm_timer_should_notify_user(struct kvm_vcpu *vcpu)
@@ -1364,22 +1369,29 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
* The host kernel runs at EL2 with HCR_EL2.TGE == 1,
* and this makes those bits have no effect for the host kernel execution.
*/
-static void kvm_timer_enable_traps_vhe(void)
+static void kvm_timer_enable_traps_vhe(struct kvm_vcpu *vcpu)
{
/* When HCR_EL2.E2H ==1, EL1PCEN and EL1PCTEN are shifted by 10 */
u32 cnthctl_shift = 10;
- u64 val;
+ u64 val, mask;
+
+ mask = CNTHCTL_EL1PCEN << cnthctl_shift;
+ mask |= CNTHCTL_EL1PCTEN << cnthctl_shift;
- /*
- * VHE systems allow the guest direct access to the EL1 physical
- * timer/counter.
- */
val = read_sysreg(cnthctl_el2);
- val |= (CNTHCTL_EL1PCEN << cnthctl_shift);
- val |= (CNTHCTL_EL1PCTEN << cnthctl_shift);
if (cpus_have_final_cap(ARM64_HAS_ECV2))
val |= CNTHCTL_ECV;
+
+ /*
+ * VHE systems allow the guest direct access to the EL1 physical
+ * timer/counter if offsetting isn't requested on a non-ECV system.
+ */
+ if (ptimer_emulation_required(vcpu))
+ val &= ~mask;
+ else
+ val |= mask;
+
write_sysreg(val, cnthctl_el2);
}
@@ -1434,9 +1446,6 @@ static int kvm_arm_timer_set_attr_offset(struct kvm_vcpu *vcpu,
u64 __user *uaddr = (u64 __user *)(long)attr->addr;
u64 offset;
- if (!kvm_timer_physical_offset_allowed())
- return -ENXIO;
-
if (get_user(offset, uaddr))
return -EFAULT;
@@ -1485,9 +1494,6 @@ static int kvm_arm_timer_get_attr_offset(struct kvm_vcpu *vcpu,
u64 __user *uaddr = (u64 __user *)(long)attr->addr;
u64 offset;
- if (!kvm_timer_physical_offset_allowed())
- return -ENXIO;
-
offset = timer_get_offset(vcpu_ptimer(vcpu));
return put_user(offset, uaddr);
}
@@ -1511,11 +1517,8 @@ int kvm_arm_timer_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
switch (attr->attr) {
case KVM_ARM_VCPU_TIMER_IRQ_VTIMER:
case KVM_ARM_VCPU_TIMER_IRQ_PTIMER:
- return 0;
case KVM_ARM_VCPU_TIMER_PHYS_OFFSET:
- if (kvm_timer_physical_offset_allowed())
- return 0;
- break;
+ return 0;
}
return -ENXIO;
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index a0e78a6027be..9c42a299957c 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -15,6 +15,7 @@
#include <linux/jump_label.h>
#include <uapi/linux/psci.h>
+#include <kvm/arm_arch_timer.h>
#include <kvm/arm_psci.h>
#include <asm/barrier.h>
@@ -409,6 +410,34 @@ static inline bool __hyp_handle_ptrauth(struct kvm_vcpu *vcpu)
return true;
}
+static inline u64 __timer_read_cntpct(struct kvm_vcpu *vcpu)
+{
+ return __arch_counter_get_cntpct() - vcpu_ptimer(vcpu)->host_offset;
+}
+
+static inline bool __hyp_handle_counter(struct kvm_vcpu *vcpu)
+{
+ u32 sysreg;
+ int rt;
+ u64 rv;
+
+ if (kvm_timer_physical_offset_allowed())
+ return false;
+
+ if (kvm_vcpu_trap_get_class(vcpu) != ESR_ELx_EC_SYS64)
+ return false;
+
+ sysreg = esr_sys64_to_sysreg(kvm_vcpu_get_esr(vcpu));
+ if (sysreg != SYS_CNTPCT_EL0 && sysreg != SYS_CNTPCTSS_EL0)
+ return false;
+
+ rt = kvm_vcpu_sys_get_rt(vcpu);
+ rv = __timer_read_cntpct(vcpu);
+ vcpu_set_reg(vcpu, rt, rv);
+ __kvm_skip_instr(vcpu);
+ return true;
+}
+
/*
* Return true when we were able to fixup the guest exit and should return to
* the guest, false when we should restore the host state and return to the
@@ -443,6 +472,9 @@ static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
if (*exit_code != ARM_EXCEPTION_TRAP)
goto exit;
+ if (__hyp_handle_counter(vcpu))
+ goto guest;
+
if (cpus_have_final_cap(ARM64_WORKAROUND_CAVIUM_TX2_219_TVM) &&
kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_SYS64 &&
handle_tx2_tvm(vcpu))
diff --git a/arch/arm64/kvm/hyp/nvhe/timer-sr.c b/arch/arm64/kvm/hyp/nvhe/timer-sr.c
index 9072e71693ba..6c0834421eae 100644
--- a/arch/arm64/kvm/hyp/nvhe/timer-sr.c
+++ b/arch/arm64/kvm/hyp/nvhe/timer-sr.c
@@ -39,10 +39,17 @@ void __timer_enable_traps(struct kvm_vcpu *vcpu)
/*
* Disallow physical timer access for the guest
- * Physical counter access is allowed
*/
val = read_sysreg(cnthctl_el2);
val &= ~CNTHCTL_EL1PCEN;
- val |= CNTHCTL_EL1PCTEN;
+
+ /*
+ * Disallow physical counter access for the guest if offsetting is
+ * requested on a non-ECV system.
+ */
+ if (ptimer_emulation_required(vcpu))
+ val &= ~CNTHCTL_EL1PCTEN;
+ else
+ val |= CNTHCTL_EL1PCTEN;
write_sysreg(val, cnthctl_el2);
}
diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index d06294aa356e..252c012db505 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -96,6 +96,9 @@ bool kvm_arch_timer_get_input_level(int vintid);
#define arch_timer_ctx_index(ctx) ((ctx) - vcpu_timer((ctx)->vcpu)->timers)
+#define ptimer_emulation_required(v) \
+ (!cpus_have_final_cap(ARM64_HAS_ECV2) && vcpu_ptimer(v)->host_offset)
+
u64 kvm_arm_timer_read_sysreg(struct kvm_vcpu *vcpu,
enum kvm_arch_timers tmr,
enum kvm_arch_timer_regs treg);
--
2.33.0.309.g3052b89438-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
WARNING: multiple messages have this Message-ID (diff)
From: Oliver Upton <oupton@google.com>
To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu
Cc: Paolo Bonzini <pbonzini@redhat.com>,
Sean Christopherson <seanjc@google.com>,
Marc Zyngier <maz@kernel.org>, Peter Shier <pshier@google.com>,
Jim Mattson <jmattson@google.com>,
David Matlack <dmatlack@google.com>,
Ricardo Koller <ricarkol@google.com>,
Jing Zhang <jingzhangos@google.com>,
Raghavendra Rao Anata <rananta@google.com>,
James Morse <james.morse@arm.com>,
Alexandru Elisei <alexandru.elisei@arm.com>,
Suzuki K Poulose <suzuki.poulose@arm.com>,
linux-arm-kernel@lists.infradead.org,
Andrew Jones <drjones@redhat.com>, Will Deacon <will@kernel.org>,
Catalin Marinas <catalin.marinas@arm.com>,
Oliver Upton <oupton@google.com>
Subject: [PATCH v8 8/8] KVM: arm64: Emulate physical counter offsetting on non-ECV systems
Date: Thu, 16 Sep 2021 18:15:10 +0000 [thread overview]
Message-ID: <20210916181510.963449-9-oupton@google.com> (raw)
In-Reply-To: <20210916181510.963449-1-oupton@google.com>
Unfortunately, ECV hasn't yet arrived in any tangible hardware. At the
same time, controlling the guest view of the physical counter-timer is
useful. Support guest counter-timer offsetting on non-ECV systems by
trapping guest accesses to the physical counter-timer. Emulate reads of
the physical counter in the fast exit path.
Signed-off-by: Oliver Upton <oupton@google.com>
Reviewed-by: Andrew Jones <drjones@redhat.com>
---
arch/arm64/include/asm/sysreg.h | 2 ++
arch/arm64/kvm/arch_timer.c | 47 +++++++++++++------------
arch/arm64/kvm/hyp/include/hyp/switch.h | 32 +++++++++++++++++
arch/arm64/kvm/hyp/nvhe/timer-sr.c | 11 ++++--
include/kvm/arm_arch_timer.h | 3 ++
5 files changed, 71 insertions(+), 24 deletions(-)
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index d5a686dff57e..cb9f72ebd6ec 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -506,6 +506,8 @@
#define SYS_AMEVCNTR0_MEM_STALL SYS_AMEVCNTR0_EL0(3)
#define SYS_CNTFRQ_EL0 sys_reg(3, 3, 14, 0, 0)
+#define SYS_CNTPCT_EL0 sys_reg(3, 3, 14, 0, 1)
+#define SYS_CNTPCTSS_EL0 sys_reg(3, 3, 14, 0, 5)
#define SYS_CNTP_TVAL_EL0 sys_reg(3, 3, 14, 2, 0)
#define SYS_CNTP_CTL_EL0 sys_reg(3, 3, 14, 2, 1)
diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index 68fb5ddb9e7a..2280a99ab98b 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -51,7 +51,7 @@ static void kvm_arm_timer_write(struct kvm_vcpu *vcpu,
static u64 kvm_arm_timer_read(struct kvm_vcpu *vcpu,
struct arch_timer_context *timer,
enum kvm_arch_timer_regs treg);
-static void kvm_timer_enable_traps_vhe(void);
+static void kvm_timer_enable_traps_vhe(struct kvm_vcpu *vcpu);
u32 timer_get_ctl(struct arch_timer_context *ctxt)
{
@@ -179,8 +179,13 @@ 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;
+ if (!ptimer_emulation_required(vcpu)) {
+ map->direct_ptimer = vcpu_ptimer(vcpu);
+ map->emul_ptimer = NULL;
+ } else {
+ map->direct_ptimer = NULL;
+ map->emul_ptimer = vcpu_ptimer(vcpu);
+ }
} else {
map->direct_vtimer = vcpu_vtimer(vcpu);
map->direct_ptimer = NULL;
@@ -666,7 +671,7 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
timer_emulate(map.emul_ptimer);
if (has_vhe())
- kvm_timer_enable_traps_vhe();
+ kvm_timer_enable_traps_vhe(vcpu);
}
bool kvm_timer_should_notify_user(struct kvm_vcpu *vcpu)
@@ -1364,22 +1369,29 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
* The host kernel runs at EL2 with HCR_EL2.TGE == 1,
* and this makes those bits have no effect for the host kernel execution.
*/
-static void kvm_timer_enable_traps_vhe(void)
+static void kvm_timer_enable_traps_vhe(struct kvm_vcpu *vcpu)
{
/* When HCR_EL2.E2H ==1, EL1PCEN and EL1PCTEN are shifted by 10 */
u32 cnthctl_shift = 10;
- u64 val;
+ u64 val, mask;
+
+ mask = CNTHCTL_EL1PCEN << cnthctl_shift;
+ mask |= CNTHCTL_EL1PCTEN << cnthctl_shift;
- /*
- * VHE systems allow the guest direct access to the EL1 physical
- * timer/counter.
- */
val = read_sysreg(cnthctl_el2);
- val |= (CNTHCTL_EL1PCEN << cnthctl_shift);
- val |= (CNTHCTL_EL1PCTEN << cnthctl_shift);
if (cpus_have_final_cap(ARM64_HAS_ECV2))
val |= CNTHCTL_ECV;
+
+ /*
+ * VHE systems allow the guest direct access to the EL1 physical
+ * timer/counter if offsetting isn't requested on a non-ECV system.
+ */
+ if (ptimer_emulation_required(vcpu))
+ val &= ~mask;
+ else
+ val |= mask;
+
write_sysreg(val, cnthctl_el2);
}
@@ -1434,9 +1446,6 @@ static int kvm_arm_timer_set_attr_offset(struct kvm_vcpu *vcpu,
u64 __user *uaddr = (u64 __user *)(long)attr->addr;
u64 offset;
- if (!kvm_timer_physical_offset_allowed())
- return -ENXIO;
-
if (get_user(offset, uaddr))
return -EFAULT;
@@ -1485,9 +1494,6 @@ static int kvm_arm_timer_get_attr_offset(struct kvm_vcpu *vcpu,
u64 __user *uaddr = (u64 __user *)(long)attr->addr;
u64 offset;
- if (!kvm_timer_physical_offset_allowed())
- return -ENXIO;
-
offset = timer_get_offset(vcpu_ptimer(vcpu));
return put_user(offset, uaddr);
}
@@ -1511,11 +1517,8 @@ int kvm_arm_timer_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
switch (attr->attr) {
case KVM_ARM_VCPU_TIMER_IRQ_VTIMER:
case KVM_ARM_VCPU_TIMER_IRQ_PTIMER:
- return 0;
case KVM_ARM_VCPU_TIMER_PHYS_OFFSET:
- if (kvm_timer_physical_offset_allowed())
- return 0;
- break;
+ return 0;
}
return -ENXIO;
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index a0e78a6027be..9c42a299957c 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -15,6 +15,7 @@
#include <linux/jump_label.h>
#include <uapi/linux/psci.h>
+#include <kvm/arm_arch_timer.h>
#include <kvm/arm_psci.h>
#include <asm/barrier.h>
@@ -409,6 +410,34 @@ static inline bool __hyp_handle_ptrauth(struct kvm_vcpu *vcpu)
return true;
}
+static inline u64 __timer_read_cntpct(struct kvm_vcpu *vcpu)
+{
+ return __arch_counter_get_cntpct() - vcpu_ptimer(vcpu)->host_offset;
+}
+
+static inline bool __hyp_handle_counter(struct kvm_vcpu *vcpu)
+{
+ u32 sysreg;
+ int rt;
+ u64 rv;
+
+ if (kvm_timer_physical_offset_allowed())
+ return false;
+
+ if (kvm_vcpu_trap_get_class(vcpu) != ESR_ELx_EC_SYS64)
+ return false;
+
+ sysreg = esr_sys64_to_sysreg(kvm_vcpu_get_esr(vcpu));
+ if (sysreg != SYS_CNTPCT_EL0 && sysreg != SYS_CNTPCTSS_EL0)
+ return false;
+
+ rt = kvm_vcpu_sys_get_rt(vcpu);
+ rv = __timer_read_cntpct(vcpu);
+ vcpu_set_reg(vcpu, rt, rv);
+ __kvm_skip_instr(vcpu);
+ return true;
+}
+
/*
* Return true when we were able to fixup the guest exit and should return to
* the guest, false when we should restore the host state and return to the
@@ -443,6 +472,9 @@ static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
if (*exit_code != ARM_EXCEPTION_TRAP)
goto exit;
+ if (__hyp_handle_counter(vcpu))
+ goto guest;
+
if (cpus_have_final_cap(ARM64_WORKAROUND_CAVIUM_TX2_219_TVM) &&
kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_SYS64 &&
handle_tx2_tvm(vcpu))
diff --git a/arch/arm64/kvm/hyp/nvhe/timer-sr.c b/arch/arm64/kvm/hyp/nvhe/timer-sr.c
index 9072e71693ba..6c0834421eae 100644
--- a/arch/arm64/kvm/hyp/nvhe/timer-sr.c
+++ b/arch/arm64/kvm/hyp/nvhe/timer-sr.c
@@ -39,10 +39,17 @@ void __timer_enable_traps(struct kvm_vcpu *vcpu)
/*
* Disallow physical timer access for the guest
- * Physical counter access is allowed
*/
val = read_sysreg(cnthctl_el2);
val &= ~CNTHCTL_EL1PCEN;
- val |= CNTHCTL_EL1PCTEN;
+
+ /*
+ * Disallow physical counter access for the guest if offsetting is
+ * requested on a non-ECV system.
+ */
+ if (ptimer_emulation_required(vcpu))
+ val &= ~CNTHCTL_EL1PCTEN;
+ else
+ val |= CNTHCTL_EL1PCTEN;
write_sysreg(val, cnthctl_el2);
}
diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h
index d06294aa356e..252c012db505 100644
--- a/include/kvm/arm_arch_timer.h
+++ b/include/kvm/arm_arch_timer.h
@@ -96,6 +96,9 @@ bool kvm_arch_timer_get_input_level(int vintid);
#define arch_timer_ctx_index(ctx) ((ctx) - vcpu_timer((ctx)->vcpu)->timers)
+#define ptimer_emulation_required(v) \
+ (!cpus_have_final_cap(ARM64_HAS_ECV2) && vcpu_ptimer(v)->host_offset)
+
u64 kvm_arm_timer_read_sysreg(struct kvm_vcpu *vcpu,
enum kvm_arch_timers tmr,
enum kvm_arch_timer_regs treg);
--
2.33.0.309.g3052b89438-goog
next prev parent reply other threads:[~2021-09-16 18:15 UTC|newest]
Thread overview: 51+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-09-16 18:15 [PATCH v8 0/8] KVM: arm64: Add idempotent controls to migrate guest counter Oliver Upton
2021-09-16 18:15 ` Oliver Upton
2021-09-16 18:15 ` Oliver Upton
2021-09-16 18:15 ` [PATCH v8 1/8] KVM: arm64: Refactor update_vtimer_cntvoff() Oliver Upton
2021-09-16 18:15 ` Oliver Upton
2021-09-16 18:15 ` Oliver Upton
2021-09-16 18:15 ` [PATCH v8 2/8] KVM: arm64: Separate guest/host counter offset values Oliver Upton
2021-09-16 18:15 ` Oliver Upton
2021-09-16 18:15 ` Oliver Upton
2021-09-22 4:37 ` Reiji Watanabe
2021-09-22 4:37 ` Reiji Watanabe
2021-09-22 4:37 ` Reiji Watanabe
2021-09-22 14:44 ` Sean Christopherson
2021-09-22 14:44 ` Sean Christopherson
2021-09-22 14:44 ` Sean Christopherson
2021-09-22 16:17 ` Alexandru Elisei
2021-09-22 16:17 ` Alexandru Elisei
2021-09-22 16:17 ` Alexandru Elisei
2021-09-16 18:15 ` [PATCH v8 3/8] KVM: arm64: Make a helper function to get nr of timer regs Oliver Upton
2021-09-16 18:15 ` Oliver Upton
2021-09-16 18:15 ` Oliver Upton
2021-10-05 6:30 ` Andrew Jones
2021-10-05 6:30 ` Andrew Jones
2021-10-05 6:30 ` Andrew Jones
2021-09-16 18:15 ` [PATCH v8 4/8] KVM: arm64: Allow userspace to configure a vCPU's virtual offset Oliver Upton
2021-09-16 18:15 ` Oliver Upton
2021-09-16 18:15 ` Oliver Upton
2021-09-16 18:15 ` [PATCH v8 5/8] arm64: cpufeature: Enumerate support for FEAT_ECV >= 0x2 Oliver Upton
2021-09-16 18:15 ` Oliver Upton
2021-09-16 18:15 ` Oliver Upton
2021-10-13 5:10 ` Reiji Watanabe
2021-10-13 5:10 ` Reiji Watanabe
2021-10-13 5:10 ` Reiji Watanabe
2021-09-16 18:15 ` [PATCH v8 6/8] KVM: arm64: Allow userspace to configure a guest's counter-timer offset Oliver Upton
2021-09-16 18:15 ` Oliver Upton
2021-09-16 18:15 ` Oliver Upton
2021-09-22 16:39 ` Reiji Watanabe
2021-09-22 16:39 ` Reiji Watanabe
2021-09-22 16:39 ` Reiji Watanabe
2021-09-24 7:20 ` Reiji Watanabe
2021-09-24 7:20 ` Reiji Watanabe
2021-09-24 7:20 ` Reiji Watanabe
2021-09-16 18:15 ` [PATCH v8 7/8] KVM: arm64: Configure timer traps in vcpu_load() for VHE Oliver Upton
2021-09-16 18:15 ` Oliver Upton
2021-09-16 18:15 ` Oliver Upton
2021-09-16 18:15 ` Oliver Upton [this message]
2021-09-16 18:15 ` [PATCH v8 8/8] KVM: arm64: Emulate physical counter offsetting on non-ECV systems Oliver Upton
2021-09-16 18:15 ` Oliver Upton
2021-09-22 15:27 ` [PATCH v8 0/8] KVM: arm64: Add idempotent controls to migrate guest counter Alexandru Elisei
2021-09-22 15:27 ` Alexandru Elisei
2021-09-22 15:27 ` Alexandru Elisei
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210916181510.963449-9-oupton@google.com \
--to=oupton@google.com \
--cc=catalin.marinas@arm.com \
--cc=dmatlack@google.com \
--cc=jmattson@google.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.cs.columbia.edu \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=maz@kernel.org \
--cc=pbonzini@redhat.com \
--cc=pshier@google.com \
--cc=seanjc@google.com \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.