[PATCH RFC 08/39] KVM: x86/xen: register steal clock

From: Joao Martins
Date: Wed Feb 20 2019 - 15:17:39 EST


Allow emulator to register vcpu runstates which allow Xen guests
to use that for steal clock. The 'preempted' state of KVM steal clock
equates to 'runnable' state, 'running' has similar meanings for both and
'offline' is used when system admin needs to bring vcpu offline or
hotplug.

Signed-off-by: Joao Martins <joao.m.martins@xxxxxxxxxx>
---
arch/x86/include/asm/kvm_host.h | 2 ++
arch/x86/kvm/x86.c | 10 ++++++++
arch/x86/kvm/xen.c | 51 +++++++++++++++++++++++++++++++++++++++++
arch/x86/kvm/xen.h | 2 ++
include/uapi/linux/kvm.h | 1 +
5 files changed, 66 insertions(+)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index f39d50dd8f40..9d388ba0a05c 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -541,6 +541,8 @@ struct kvm_vcpu_xen {
struct vcpu_info *vcpu_info;
gpa_t pv_time_addr;
struct pvclock_vcpu_time_info *pv_time;
+ gpa_t steal_time_addr;
+ struct vcpu_runstate_info *steal_time;
};

struct kvm_vcpu_arch {
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 3ce97860e6ee..888598fdf543 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2389,6 +2389,11 @@ static void kvm_vcpu_flush_tlb(struct kvm_vcpu *vcpu, bool invalidate_gpa)

static void record_steal_time(struct kvm_vcpu *vcpu)
{
+ if (vcpu->arch.xen.steal_time_addr) {
+ kvm_xen_setup_runstate_page(vcpu);
+ return;
+ }
+
if (!(vcpu->arch.st.msr_val & KVM_MSR_ENABLED))
return;

@@ -3251,6 +3256,11 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)

static void kvm_steal_time_set_preempted(struct kvm_vcpu *vcpu)
{
+ if (vcpu->arch.xen.steal_time_addr) {
+ kvm_xen_runstate_set_preempted(vcpu);
+ return;
+ }
+
if (!(vcpu->arch.st.msr_val & KVM_MSR_ENABLED))
return;

diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c
index 77d1153386bc..4fdc4c71245a 100644
--- a/arch/x86/kvm/xen.c
+++ b/arch/x86/kvm/xen.c
@@ -9,9 +9,11 @@
#include "xen.h"

#include <linux/kvm_host.h>
+#include <linux/sched/stat.h>

#include <trace/events/kvm.h>
#include <xen/interface/xen.h>
+#include <xen/interface/vcpu.h>

#include "trace.h"

@@ -30,6 +32,11 @@ static void set_vcpu_attr(struct kvm_vcpu *v, u16 type, gpa_t gpa, void *addr)
vcpu_xen->pv_time = addr;
kvm_xen_setup_pvclock_page(v);
break;
+ case KVM_XEN_ATTR_TYPE_VCPU_RUNSTATE:
+ vcpu_xen->steal_time_addr = gpa;
+ vcpu_xen->steal_time = addr;
+ kvm_xen_setup_runstate_page(v);
+ break;
default:
break;
}
@@ -44,6 +51,8 @@ static gpa_t get_vcpu_attr(struct kvm_vcpu *v, u16 type)
return vcpu_xen->vcpu_info_addr;
case KVM_XEN_ATTR_TYPE_VCPU_TIME_INFO:
return vcpu_xen->pv_time_addr;
+ case KVM_XEN_ATTR_TYPE_VCPU_RUNSTATE:
+ return vcpu_xen->steal_time_addr;
default:
return 0;
}
@@ -124,6 +133,41 @@ static void kvm_xen_update_vcpu_time(struct kvm_vcpu *v,
guest_hv_clock->version = vcpu->hv_clock.version;
}

+void kvm_xen_runstate_set_preempted(struct kvm_vcpu *vcpu)
+{
+ struct kvm_vcpu_xen *vcpu_xen = vcpu_to_xen_vcpu(vcpu);
+ int state = RUNSTATE_runnable;
+
+ vcpu->arch.st.steal.preempted = KVM_VCPU_PREEMPTED;
+
+ vcpu_xen->steal_time->state = state;
+}
+
+void kvm_xen_setup_runstate_page(struct kvm_vcpu *vcpu)
+{
+ struct kvm_vcpu_xen *vcpu_xen = vcpu_to_xen_vcpu(vcpu);
+ struct vcpu_runstate_info runstate;
+
+ runstate = *vcpu_xen->steal_time;
+
+ runstate.state_entry_time += 1;
+ runstate.state_entry_time |= XEN_RUNSTATE_UPDATE;
+ vcpu_xen->steal_time->state_entry_time = runstate.state_entry_time;
+ smp_wmb();
+
+ vcpu->arch.st.steal.steal += current->sched_info.run_delay -
+ vcpu->arch.st.last_steal;
+ vcpu->arch.st.last_steal = current->sched_info.run_delay;
+
+ runstate.state = RUNSTATE_running;
+ runstate.time[RUNSTATE_runnable] = vcpu->arch.st.steal.steal;
+ *vcpu_xen->steal_time = runstate;
+
+ runstate.state_entry_time &= ~XEN_RUNSTATE_UPDATE;
+ vcpu_xen->steal_time->state_entry_time = runstate.state_entry_time;
+ smp_wmb();
+}
+
void kvm_xen_setup_pvclock_page(struct kvm_vcpu *v)
{
struct kvm_vcpu_xen *vcpu_xen = vcpu_to_xen_vcpu(v);
@@ -155,6 +199,10 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
r = kvm_xen_shared_info_init(kvm, gfn);
break;
}
+ case KVM_XEN_ATTR_TYPE_VCPU_RUNSTATE:
+ if (unlikely(!sched_info_on()))
+ return -ENOTSUPP;
+ /* fallthrough */
case KVM_XEN_ATTR_TYPE_VCPU_TIME_INFO:
case KVM_XEN_ATTR_TYPE_VCPU_INFO: {
gpa_t gpa = data->u.vcpu_attr.gpa;
@@ -191,6 +239,7 @@ int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
data->u.shared_info.gfn = kvm->arch.xen.shinfo_addr;
break;
}
+ case KVM_XEN_ATTR_TYPE_VCPU_RUNSTATE:
case KVM_XEN_ATTR_TYPE_VCPU_TIME_INFO:
case KVM_XEN_ATTR_TYPE_VCPU_INFO: {
struct kvm_vcpu *v;
@@ -282,6 +331,8 @@ void kvm_xen_vcpu_uninit(struct kvm_vcpu *vcpu)
put_page(virt_to_page(vcpu_xen->vcpu_info));
if (vcpu_xen->pv_time)
put_page(virt_to_page(vcpu_xen->pv_time));
+ if (vcpu_xen->steal_time)
+ put_page(virt_to_page(vcpu_xen->steal_time));
}

void kvm_xen_destroy_vm(struct kvm *kvm)
diff --git a/arch/x86/kvm/xen.h b/arch/x86/kvm/xen.h
index 10ebd0b7a25e..2feef68ee80f 100644
--- a/arch/x86/kvm/xen.h
+++ b/arch/x86/kvm/xen.h
@@ -17,6 +17,8 @@ static inline struct kvm_vcpu *xen_vcpu_to_vcpu(struct kvm_vcpu_xen *xen_vcpu)
}

void kvm_xen_setup_pvclock_page(struct kvm_vcpu *vcpu);
+void kvm_xen_setup_runstate_page(struct kvm_vcpu *vcpu);
+void kvm_xen_runstate_set_preempted(struct kvm_vcpu *vcpu);
int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data);
int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data);
bool kvm_xen_hypercall_enabled(struct kvm *kvm);
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 8296c3a2434f..b91e57d9e6d3 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1475,6 +1475,7 @@ struct kvm_xen_hvm_attr {
#define KVM_XEN_ATTR_TYPE_SHARED_INFO 0x0
#define KVM_XEN_ATTR_TYPE_VCPU_INFO 0x1
#define KVM_XEN_ATTR_TYPE_VCPU_TIME_INFO 0x2
+#define KVM_XEN_ATTR_TYPE_VCPU_RUNSTATE 0x3

/* Secure Encrypted Virtualization command */
enum sev_cmd_id {
--
2.11.0