Commit db397571 authored by Andrey Smetanin's avatar Andrey Smetanin Committed by Paolo Bonzini

kvm/x86: Hyper-V kvm exit

A new vcpu exit is introduced to notify the userspace of the
changes in Hyper-V SynIC configuration triggered by guest writing to the
corresponding MSRs.

Changes v4:
* exit into userspace only if guest writes into SynIC MSR's

Changes v3:
* added KVM_EXIT_HYPERV types and structs notes into docs
Signed-off-by: default avatarAndrey Smetanin <asmetanin@virtuozzo.com>
Reviewed-by: default avatarRoman Kagan <rkagan@virtuozzo.com>
Signed-off-by: default avatarDenis V. Lunev <den@openvz.org>
CC: Gleb Natapov <gleb@kernel.org>
CC: Paolo Bonzini <pbonzini@redhat.com>
CC: Roman Kagan <rkagan@virtuozzo.com>
CC: Denis V. Lunev <den@openvz.org>
CC: qemu-devel@nongnu.org
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 5c919412
...@@ -3337,6 +3337,28 @@ the userspace IOAPIC should process the EOI and retrigger the interrupt if ...@@ -3337,6 +3337,28 @@ the userspace IOAPIC should process the EOI and retrigger the interrupt if
it is still asserted. Vector is the LAPIC interrupt vector for which the it is still asserted. Vector is the LAPIC interrupt vector for which the
EOI was received. EOI was received.
struct kvm_hyperv_exit {
#define KVM_EXIT_HYPERV_SYNIC 1
__u32 type;
union {
struct {
__u32 msr;
__u64 control;
__u64 evt_page;
__u64 msg_page;
} synic;
} u;
};
/* KVM_EXIT_HYPERV */
struct kvm_hyperv_exit hyperv;
Indicates that the VCPU exits into userspace to process some tasks
related to Hyper-V emulation.
Valid values for 'type' are:
KVM_EXIT_HYPERV_SYNIC -- synchronously notify user-space about
Hyper-V SynIC state change. Notification is used to remap SynIC
event/message pages and to enable/disable SynIC messages/events processing
in userspace.
/* Fix the size of the union. */ /* Fix the size of the union. */
char padding[256]; char padding[256];
}; };
......
...@@ -393,6 +393,7 @@ struct kvm_vcpu_hv { ...@@ -393,6 +393,7 @@ struct kvm_vcpu_hv {
u64 hv_vapic; u64 hv_vapic;
s64 runtime_offset; s64 runtime_offset;
struct kvm_vcpu_hv_synic synic; struct kvm_vcpu_hv_synic synic;
struct kvm_hyperv_exit exit;
}; };
struct kvm_vcpu_arch { struct kvm_vcpu_arch {
......
...@@ -130,6 +130,20 @@ static void kvm_hv_notify_acked_sint(struct kvm_vcpu *vcpu, u32 sint) ...@@ -130,6 +130,20 @@ static void kvm_hv_notify_acked_sint(struct kvm_vcpu *vcpu, u32 sint)
srcu_read_unlock(&kvm->irq_srcu, idx); srcu_read_unlock(&kvm->irq_srcu, idx);
} }
static void synic_exit(struct kvm_vcpu_hv_synic *synic, u32 msr)
{
struct kvm_vcpu *vcpu = synic_to_vcpu(synic);
struct kvm_vcpu_hv *hv_vcpu = &vcpu->arch.hyperv;
hv_vcpu->exit.type = KVM_EXIT_HYPERV_SYNIC;
hv_vcpu->exit.u.synic.msr = msr;
hv_vcpu->exit.u.synic.control = synic->control;
hv_vcpu->exit.u.synic.evt_page = synic->evt_page;
hv_vcpu->exit.u.synic.msg_page = synic->msg_page;
kvm_make_request(KVM_REQ_HV_EXIT, vcpu);
}
static int synic_set_msr(struct kvm_vcpu_hv_synic *synic, static int synic_set_msr(struct kvm_vcpu_hv_synic *synic,
u32 msr, u64 data, bool host) u32 msr, u64 data, bool host)
{ {
...@@ -145,6 +159,8 @@ static int synic_set_msr(struct kvm_vcpu_hv_synic *synic, ...@@ -145,6 +159,8 @@ static int synic_set_msr(struct kvm_vcpu_hv_synic *synic,
switch (msr) { switch (msr) {
case HV_X64_MSR_SCONTROL: case HV_X64_MSR_SCONTROL:
synic->control = data; synic->control = data;
if (!host)
synic_exit(synic, msr);
break; break;
case HV_X64_MSR_SVERSION: case HV_X64_MSR_SVERSION:
if (!host) { if (!host) {
...@@ -161,6 +177,8 @@ static int synic_set_msr(struct kvm_vcpu_hv_synic *synic, ...@@ -161,6 +177,8 @@ static int synic_set_msr(struct kvm_vcpu_hv_synic *synic,
break; break;
} }
synic->evt_page = data; synic->evt_page = data;
if (!host)
synic_exit(synic, msr);
break; break;
case HV_X64_MSR_SIMP: case HV_X64_MSR_SIMP:
if (data & HV_SYNIC_SIMP_ENABLE) if (data & HV_SYNIC_SIMP_ENABLE)
...@@ -170,6 +188,8 @@ static int synic_set_msr(struct kvm_vcpu_hv_synic *synic, ...@@ -170,6 +188,8 @@ static int synic_set_msr(struct kvm_vcpu_hv_synic *synic,
break; break;
} }
synic->msg_page = data; synic->msg_page = data;
if (!host)
synic_exit(synic, msr);
break; break;
case HV_X64_MSR_EOM: { case HV_X64_MSR_EOM: {
int i; int i;
......
...@@ -6482,6 +6482,12 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) ...@@ -6482,6 +6482,12 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
r = 0; r = 0;
goto out; goto out;
} }
if (kvm_check_request(KVM_REQ_HV_EXIT, vcpu)) {
vcpu->run->exit_reason = KVM_EXIT_HYPERV;
vcpu->run->hyperv = vcpu->arch.hyperv.exit;
r = 0;
goto out;
}
} }
/* /*
......
...@@ -143,6 +143,7 @@ static inline bool is_error_page(struct page *page) ...@@ -143,6 +143,7 @@ static inline bool is_error_page(struct page *page)
#define KVM_REQ_HV_CRASH 27 #define KVM_REQ_HV_CRASH 27
#define KVM_REQ_IOAPIC_EOI_EXIT 28 #define KVM_REQ_IOAPIC_EOI_EXIT 28
#define KVM_REQ_HV_RESET 29 #define KVM_REQ_HV_RESET 29
#define KVM_REQ_HV_EXIT 30
#define KVM_USERSPACE_IRQ_SOURCE_ID 0 #define KVM_USERSPACE_IRQ_SOURCE_ID 0
#define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID 1 #define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID 1
......
...@@ -154,6 +154,20 @@ struct kvm_s390_skeys { ...@@ -154,6 +154,20 @@ struct kvm_s390_skeys {
__u32 flags; __u32 flags;
__u32 reserved[9]; __u32 reserved[9];
}; };
struct kvm_hyperv_exit {
#define KVM_EXIT_HYPERV_SYNIC 1
__u32 type;
union {
struct {
__u32 msr;
__u64 control;
__u64 evt_page;
__u64 msg_page;
} synic;
} u;
};
#define KVM_S390_GET_SKEYS_NONE 1 #define KVM_S390_GET_SKEYS_NONE 1
#define KVM_S390_SKEYS_MAX 1048576 #define KVM_S390_SKEYS_MAX 1048576
...@@ -184,6 +198,7 @@ struct kvm_s390_skeys { ...@@ -184,6 +198,7 @@ struct kvm_s390_skeys {
#define KVM_EXIT_SYSTEM_EVENT 24 #define KVM_EXIT_SYSTEM_EVENT 24
#define KVM_EXIT_S390_STSI 25 #define KVM_EXIT_S390_STSI 25
#define KVM_EXIT_IOAPIC_EOI 26 #define KVM_EXIT_IOAPIC_EOI 26
#define KVM_EXIT_HYPERV 27
/* For KVM_EXIT_INTERNAL_ERROR */ /* For KVM_EXIT_INTERNAL_ERROR */
/* Emulate instruction failed. */ /* Emulate instruction failed. */
...@@ -338,6 +353,8 @@ struct kvm_run { ...@@ -338,6 +353,8 @@ struct kvm_run {
struct { struct {
__u8 vector; __u8 vector;
} eoi; } eoi;
/* KVM_EXIT_HYPERV */
struct kvm_hyperv_exit hyperv;
/* Fix the size of the union. */ /* Fix the size of the union. */
char padding[256]; char padding[256];
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment