[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v1 3/5] target/arm/kvm: Implement cpu feature kvm-adjvtime
From: |
Andrew Jones |
Subject: |
[PATCH v1 3/5] target/arm/kvm: Implement cpu feature kvm-adjvtime |
Date: |
Wed, 16 Oct 2019 16:34:08 +0200 |
When kvm-adjvtime is enabled the guest's cntvct[_el0] won't count
the time when the VM is stopped. That time is skipped by updating
cntvoff[_el2] on each transition to vm_running using the current
QEMU_CLOCK_VIRTUAL time. QEMU_CLOCK_VIRTUAL only ticks when the VM
is running.
This patch only provides the implementation. A subsequent patch
will provide the CPU property allowing the feature to be enabled.
Reported-by: Bijan Mottahedeh <address@hidden>
Suggested-by: Bijan Mottahedeh <address@hidden>
Signed-off-by: Andrew Jones <address@hidden>
Reviewed-by: Richard Henderson <address@hidden>
---
target/arm/cpu.h | 3 +++
target/arm/kvm.c | 32 ++++++++++++++++++++++++++++++++
target/arm/kvm32.c | 3 +++
target/arm/kvm64.c | 3 +++
target/arm/kvm_arm.h | 14 ++++++++++++++
5 files changed, 55 insertions(+)
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index b3092e5213e6..7c07c7c5272e 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -821,6 +821,9 @@ struct ARMCPU {
/* KVM init features for this CPU */
uint32_t kvm_init_features[7];
+ /* KVM CPU features */
+ bool kvm_adjvtime;
+
/* Uniprocessor system with MP extensions */
bool mp_is_up;
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 5b82cefef608..373b868dc248 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -348,6 +348,18 @@ void kvm_arm_register_device(MemoryRegion *mr, uint64_t
devid, uint64_t group,
memory_region_ref(kd->mr);
}
+void kvm_arm_vm_state_change(void *opaque, int running, RunState state)
+{
+ CPUState *cs = opaque;
+ ARMCPU *cpu = ARM_CPU(cs);
+
+ if (running) {
+ if (cpu->kvm_adjvtime) {
+ kvm_arm_set_virtual_time(cs);
+ }
+ }
+}
+
static int compare_u64(const void *a, const void *b)
{
if (*(uint64_t *)a > *(uint64_t *)b) {
@@ -579,6 +591,26 @@ int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu)
return 0;
}
+void kvm_arm_set_virtual_time(CPUState *cs)
+{
+ uint64_t cnt;
+ struct kvm_one_reg reg = {
+ .id = KVM_REG_ARM_TIMER_CNT,
+ .addr = (uintptr_t)&cnt,
+ };
+ int ret;
+
+ cnt = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
+ cpu_get_host_tick_frequency(),
+ NANOSECONDS_PER_SECOND);
+
+ ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®);
+ if (ret) {
+ error_report("Failed to set KVM_REG_ARM_TIMER_CNT");
+ abort();
+ }
+}
+
int kvm_put_vcpu_events(ARMCPU *cpu)
{
CPUARMState *env = &cpu->env;
diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c
index 32bf8d6757c4..3a8b437eef0b 100644
--- a/target/arm/kvm32.c
+++ b/target/arm/kvm32.c
@@ -16,6 +16,7 @@
#include "qemu-common.h"
#include "cpu.h"
#include "qemu/timer.h"
+#include "sysemu/runstate.h"
#include "sysemu/kvm.h"
#include "kvm_arm.h"
#include "internals.h"
@@ -198,6 +199,8 @@ int kvm_arch_init_vcpu(CPUState *cs)
return -EINVAL;
}
+ qemu_add_vm_change_state_handler(kvm_arm_vm_state_change, cs);
+
/* Determine init features for this CPU */
memset(cpu->kvm_init_features, 0, sizeof(cpu->kvm_init_features));
if (cpu->start_powered_off) {
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 666a81a5ce6f..d368189fbce6 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -23,6 +23,7 @@
#include "qemu/host-utils.h"
#include "qemu/main-loop.h"
#include "exec/gdbstub.h"
+#include "sysemu/runstate.h"
#include "sysemu/kvm.h"
#include "sysemu/kvm_int.h"
#include "kvm_arm.h"
@@ -735,6 +736,8 @@ int kvm_arch_init_vcpu(CPUState *cs)
return -EINVAL;
}
+ qemu_add_vm_change_state_handler(kvm_arm_vm_state_change, cs);
+
/* Determine init features for this CPU */
memset(cpu->kvm_init_features, 0, sizeof(cpu->kvm_init_features));
if (cpu->start_powered_off) {
diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h
index 8e14d400e8ab..3bb7e331aa06 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -232,6 +232,16 @@ void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map);
*/
void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu);
+/**
+ * void kvm_arm_set_virtual_time:
+ * @cs: CPUState
+ *
+ * Sets the guest's virtual counter offset to the difference of the host's
+ * current time and QEMU's QEMU_CLOCK_VIRTUAL time. This allows the
+ * guest's virtual counter to only reflect VM running time.
+ */
+void kvm_arm_set_virtual_time(CPUState *cs);
+
/**
* kvm_arm_aarch32_supported:
* @cs: CPUState
@@ -288,6 +298,8 @@ void kvm_arm_pmu_set_irq(CPUState *cs, int irq);
void kvm_arm_pmu_init(CPUState *cs);
int kvm_arm_set_irq(int cpu, int irqtype, int irq, int level);
+void kvm_arm_vm_state_change(void *opaque, int running, RunState state);
+
#else
static inline void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
@@ -324,6 +336,8 @@ static inline int kvm_arm_vgic_probe(void)
return 0;
}
+static inline void kvm_arm_set_virtual_time(CPUState *cs) {}
+
static inline void kvm_arm_pmu_set_irq(CPUState *cs, int irq) {}
static inline void kvm_arm_pmu_init(CPUState *cs) {}
--
2.21.0
- [PATCH v1 0/5] target/arm/kvm: Provide an option to adjust virtual time, Andrew Jones, 2019/10/16
- [PATCH v1 1/5] target/arm/kvm64: kvm64 cpus have timer registers, Andrew Jones, 2019/10/16
- [PATCH v1 2/5] timer: arm: Introduce functions to get the host cntfrq, Andrew Jones, 2019/10/16
- [PATCH v1 3/5] target/arm/kvm: Implement cpu feature kvm-adjvtime,
Andrew Jones <=
- [PATCH v1 4/5] tests/arm-cpu-features: Check feature default values, Andrew Jones, 2019/10/16
- [PATCH v1 5/5] target/arm/cpu: Add the kvm-adjvtime CPU property, Andrew Jones, 2019/10/16
- Re: [PATCH v1 0/5] target/arm/kvm: Provide an option to adjust virtual time, Masayoshi Mizuma, 2019/10/17