From: Andrew Jones <drjones@redhat.com>
To: qemu-devel@nongnu.org, qemu-arm@nongnu.org
Cc: peter.maydell@linaro.org, bijan.mottahedeh@oracle.com,
maz@kernel.org, richard.henderson@linaro.org, guoheyi@huawei.com,
msys.mizuma@gmail.com
Subject: [RFC PATCH v2 3/5] target/arm/kvm: Implement virtual time adjustment
Date: Thu, 12 Dec 2019 18:33:18 +0100 [thread overview]
Message-ID: <20191212173320.11610-4-drjones@redhat.com> (raw)
In-Reply-To: <20191212173320.11610-1-drjones@redhat.com>
When a VM is stopped (guest is paused) guest virtual time
should stop counting. Otherwise, when the VM is resumed it
will experience time jumps and its kernel may report soft
lockups. Not counting virtual time while the VM is stopped
has the side effect of making the guest's time appear to lag
when compared with real time, and even with time derived from
the physical counter. For this reason, this change, which is
enabled by default, comes with a KVM CPU feature allowing it
to be disabled, restoring legacy behavior.
This patch only provides the implementation of the virtual
time adjustment. A subsequent patch will provide the CPU
property allowing the change to be enabled and disabled.
Reported-by: Bijan Mottahedeh <bijan.mottahedeh@oracle.com>
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
target/arm/cpu.h | 9 +++++++++
target/arm/kvm.c | 48 ++++++++++++++++++++++++++++++++++++++++++++
target/arm/kvm32.c | 3 +++
target/arm/kvm64.c | 3 +++
target/arm/kvm_arm.h | 23 +++++++++++++++++++++
5 files changed, 86 insertions(+)
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 83a809d4bac4..a79ea74125b3 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -821,6 +821,15 @@ struct ARMCPU {
/* KVM init features for this CPU */
uint32_t kvm_init_features[7];
+ /* KVM CPU features */
+ bool kvm_adjvtime;
+
+ /* VCPU virtual counter value used with kvm_adjvtime */
+ uint64_t kvm_vtime;
+
+ /* True if the run state is, or transitioning from, RUN_STATE_PAUSED */
+ bool runstate_paused;
+
/* Uniprocessor system with MP extensions */
bool mp_is_up;
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 5b82cefef608..a55fe7d7aefd 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -348,6 +348,24 @@ 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 && cpu->runstate_paused) {
+ kvm_arm_set_virtual_time(cs, cpu->kvm_vtime);
+ }
+ cpu->runstate_paused = false;
+ } else if (state == RUN_STATE_PAUSED) {
+ cpu->runstate_paused = true;
+ if (cpu->kvm_adjvtime) {
+ kvm_arm_get_virtual_time(cs, &cpu->kvm_vtime);
+ }
+ }
+}
+
static int compare_u64(const void *a, const void *b)
{
if (*(uint64_t *)a > *(uint64_t *)b) {
@@ -579,6 +597,36 @@ int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu)
return 0;
}
+void kvm_arm_get_virtual_time(CPUState *cs, uint64_t *cnt)
+{
+ struct kvm_one_reg reg = {
+ .id = KVM_REG_ARM_TIMER_CNT,
+ .addr = (uintptr_t)cnt,
+ };
+ int ret;
+
+ ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®);
+ if (ret) {
+ error_report("Failed to get KVM_REG_ARM_TIMER_CNT");
+ abort();
+ }
+}
+
+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;
+
+ 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 5cafcb7d36dd..e486eaf1f944 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..16b53e45377d 100644
--- a/target/arm/kvm_arm.h
+++ b/target/arm/kvm_arm.h
@@ -232,6 +232,24 @@ void kvm_arm_sve_get_vls(CPUState *cs, unsigned long *map);
*/
void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu);
+/**
+ * void kvm_arm_get_virtual_time:
+ * @cs: CPUState
+ * @cnt: the virtual counter to fill in
+ *
+ * Gets the VCPU's virtual counter and stores it in @cnt.
+ */
+void kvm_arm_get_virtual_time(CPUState *cs, uint64_t *cnt);
+
+/**
+ * void kvm_arm_set_virtual_time:
+ * @cs: CPUState
+ * @cnt: new virtual counter value
+ *
+ * Sets the VCPU's virtual counter to @cnt.
+ */
+void kvm_arm_set_virtual_time(CPUState *cs, uint64_t cnt);
+
/**
* kvm_arm_aarch32_supported:
* @cs: CPUState
@@ -288,6 +306,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 +344,9 @@ static inline int kvm_arm_vgic_probe(void)
return 0;
}
+static inline void kvm_arm_get_virtual_time(CPUState *cs, uint64_t *cnt) {}
+static inline void kvm_arm_set_virtual_time(CPUState *cs, uint64_t cnt) {}
+
static inline void kvm_arm_pmu_set_irq(CPUState *cs, int irq) {}
static inline void kvm_arm_pmu_init(CPUState *cs) {}
--
2.21.0
next prev parent reply other threads:[~2019-12-12 18:35 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-12-12 17:33 [RFC PATCH v2 0/5] target/arm/kvm: Adjust virtual time Andrew Jones
2019-12-12 17:33 ` [RFC PATCH v2 1/5] hw: add compat machines for 5.0 Andrew Jones
2019-12-12 18:27 ` David Hildenbrand
2019-12-12 19:24 ` Eduardo Habkost
2019-12-13 7:10 ` Andrew Jones
2019-12-13 5:00 ` David Gibson
2019-12-12 17:33 ` [RFC PATCH v2 2/5] target/arm/kvm64: kvm64 cpus have timer registers Andrew Jones
2019-12-12 17:33 ` Andrew Jones [this message]
2019-12-16 15:14 ` [RFC PATCH v2 3/5] target/arm/kvm: Implement virtual time adjustment Peter Maydell
2019-12-16 15:40 ` Peter Maydell
2019-12-16 16:43 ` Andrew Jones
2019-12-16 18:06 ` Peter Maydell
2019-12-19 14:30 ` Andrew Jones
2020-01-20 9:40 ` Andrew Jones
2019-12-16 16:36 ` Andrew Jones
2019-12-12 17:33 ` [RFC PATCH v2 4/5] tests/arm-cpu-features: Check feature default values Andrew Jones
2019-12-12 17:33 ` [RFC PATCH v2 5/5] target/arm/cpu: Add the kvm-no-adjvtime CPU property Andrew Jones
2019-12-16 15:06 ` Peter Maydell
2019-12-16 16:52 ` Andrew Jones
2019-12-16 16:57 ` Peter Maydell
2020-01-20 10:31 ` Andrew Jones
2020-02-06 12:08 ` Philippe Mathieu-Daudé
2020-02-06 12:40 ` Andrew Jones
2020-02-06 22:46 ` Philippe Mathieu-Daudé
2020-02-07 7:37 ` Andrew Jones
2019-12-16 15:33 ` [RFC PATCH v2 0/5] target/arm/kvm: Adjust virtual time Peter Maydell
2019-12-16 15:44 ` Peter Maydell
2020-01-20 13:45 ` Andrew Jones
2019-12-16 16:18 ` Marc Zyngier
2019-12-16 16:59 ` Andrew Jones
2019-12-16 17:05 ` Marc Zyngier
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=20191212173320.11610-4-drjones@redhat.com \
--to=drjones@redhat.com \
--cc=bijan.mottahedeh@oracle.com \
--cc=guoheyi@huawei.com \
--cc=maz@kernel.org \
--cc=msys.mizuma@gmail.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-arm@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=richard.henderson@linaro.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 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).