Skip to contentSkip to conversation

KVM: VCPU state extensions

PATCH In review Jan Kiszka 5 participants 15 messages Feb 15, 2010 – Feb 22, 2010

Subsystems (4)
lore
Share & tools
lore

Jan Kiszka

author
#0 lore raw

cover KVM: VCPU state extensions

These patches do not technically depend on each other but overlap, so I'm pushing them now in a series.

Patch 1 is a repost. Patch 2 is reworked and comes with the following changes:

- expose only a boolean to user space, mapping it on X86_SHADOW_INT_MOV_SS during write
- do not move X86_SHADOW_INT_* flags around
- Signal capability via KVM_CAP_INTR_SHADOW and manage the new kvm_vcpu_events field via KVM_VCPUEVENT_VALID_SHADOW
- Update docs

Finally, patch 3 is new, plugging the debug register migration (and reset) hole.

You can also pull from

git://git.kiszka.org/linux-kvm vcpu-state

Jan Kiszka (3):
KVM: x86: Do not return soft events in vcpu_events
KVM: x86: Save&restore interrupt shadow mask
KVM: x86: Add support for saving&restoring debug registers

 Documentation/kvm/api.txt  |   42 ++++++++++++++++++++++++-
 arch/x86/include/asm/kvm.h |   13 +++++++-
 arch/x86/kvm/vmx.c         |    2 +-
 arch/x86/kvm/x86.c         |   75 +++++++++++++++++++++++++++++++++++++++++---
 include/linux/kvm.h        |    7 ++++
 5 files changed, 131 insertions(+), 8 deletions(-)
author
#1 lore raw

PATCH 1/3 KVM: x86: Do not return soft events in vcpu_events

To avoid that user space migrates a pending software exception or interrupt, mask them out on KVM_GET_VCPU_EVENTS. Without this, user space would try to reinject them, and we would have to reconstruct the proper instruction length for VMX event injection. Now the pending event will be reinjected via executing the triggering instruction again.

---
 arch/x86/kvm/x86.c |    9 ++++++---
 1 files changed, 6 insertions(+), 3 deletions(-)
arch/x86/kvm/x86.c +6 -3
index 86b739f..50d1d2a 100644
@@ -2121,14 +2121,17 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
 {
 	vcpu_load(vcpu);
 
-	events->exception.injected = vcpu->arch.exception.pending;
+	events->exception.injected =
+		vcpu->arch.exception.pending &&
+		!kvm_exception_is_soft(vcpu->arch.exception.nr);
 	events->exception.nr = vcpu->arch.exception.nr;
 	events->exception.has_error_code = vcpu->arch.exception.has_error_code;
 	events->exception.error_code = vcpu->arch.exception.error_code;
 
-	events->interrupt.injected = vcpu->arch.interrupt.pending;
+	events->interrupt.injected =
+		vcpu->arch.interrupt.pending && !vcpu->arch.interrupt.soft;
 	events->interrupt.nr = vcpu->arch.interrupt.nr;
-	events->interrupt.soft = vcpu->arch.interrupt.soft;
+	events->interrupt.soft = 0;
 
 	events->nmi.injected = vcpu->arch.nmi_injected;
 	events->nmi.pending = vcpu->arch.nmi_pending;
Signature · 1 line
1.6.0.2
author
#2 lore raw

PATCH 2/3 KVM: x86: Save&restore interrupt shadow mask

In reply to Jan Kiszka

The interrupt shadow created by STI or MOV-SS-like operations is part of the VCPU state and must be preserved across migration. Transfer it in the spare padding field of kvm_vcpu_events.interrupt.

As a side effect we now have to make vmx_set_interrupt_shadow robust against both shadow types being set. Give MOV SS a higher priority and skip STI in that case to avoid that VMX throws a fault on next entry.

---
 Documentation/kvm/api.txt  |   11 ++++++++++-
 arch/x86/include/asm/kvm.h |    3 ++-
 arch/x86/kvm/vmx.c         |    2 +-
 arch/x86/kvm/x86.c         |   12 ++++++++++--
 include/linux/kvm.h        |    1 +
 5 files changed, 24 insertions(+), 5 deletions(-)
Documentation/kvm/api.txt +10 -1
index c6416a3..8770b67 100644
@@ -656,6 +656,7 @@ struct kvm_clock_data {
 4.29 KVM_GET_VCPU_EVENTS
 
 Capability: KVM_CAP_VCPU_EVENTS
+Extended by: KVM_CAP_INTR_SHADOW
 Architectures: x86
 Type: vm ioctl
 Parameters: struct kvm_vcpu_event (out)
@@ -676,7 +677,7 @@ struct kvm_vcpu_events {
 		__u8 injected;
 		__u8 nr;
 		__u8 soft;
-		__u8 pad;
+		__u8 shadow;
 	} interrupt;
 	struct {
 		__u8 injected;
@@ -688,9 +689,13 @@ struct kvm_vcpu_events {
 	__u32 flags;
 };
 
+KVM_VCPUEVENT_VALID_SHADOW may be set in the flags field to signal that
+interrupt.shadow contains a valid state. Otherwise, this field is undefined.
+
 4.30 KVM_SET_VCPU_EVENTS
 
 Capability: KVM_CAP_VCPU_EVENTS
+Extended by: KVM_CAP_INTR_SHADOW
 Architectures: x86
 Type: vm ioctl
 Parameters: struct kvm_vcpu_event (in)
@@ -709,6 +714,10 @@ current in-kernel state. The bits are:
 KVM_VCPUEVENT_VALID_NMI_PENDING - transfer nmi.pending to the kernel
 KVM_VCPUEVENT_VALID_SIPI_VECTOR - transfer sipi_vector
 
+If KVM_CAP_INTR_SHADOW is available, KVM_VCPUEVENT_VALID_SHADOW can be set in
+the flags field to signal that interrupt.shadow contains a valid state and
+shall be written into the VCPU.
+
 
 5. The kvm_run structure
 
arch/x86/include/asm/kvm.h +2 -1
index f46b79f..dc6cd24 100644
@@ -257,6 +257,7 @@ struct kvm_reinject_control {
 /* When set in flags, include corresponding fields on KVM_SET_VCPU_EVENTS */
 #define KVM_VCPUEVENT_VALID_NMI_PENDING	0x00000001
 #define KVM_VCPUEVENT_VALID_SIPI_VECTOR	0x00000002
+#define KVM_VCPUEVENT_VALID_SHADOW	0x00000004
 
 /* for KVM_GET/SET_VCPU_EVENTS */
 struct kvm_vcpu_events {
@@ -271,7 +272,7 @@ struct kvm_vcpu_events {
 		__u8 injected;
 		__u8 nr;
 		__u8 soft;
-		__u8 pad;
+		__u8 shadow;
 	} interrupt;
 	struct {
 		__u8 injected;
arch/x86/kvm/vmx.c +1 -1
index f82b072..0fa74d0 100644
@@ -854,7 +854,7 @@ static void vmx_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask)
 
 	if (mask & X86_SHADOW_INT_MOV_SS)
 		interruptibility |= GUEST_INTR_STATE_MOV_SS;
-	if (mask & X86_SHADOW_INT_STI)
+	else if (mask & X86_SHADOW_INT_STI)
 		interruptibility |= GUEST_INTR_STATE_STI;
 
 	if ((interruptibility != interruptibility_old))
arch/x86/kvm/x86.c +10 -2
index 50d1d2a..60e6341 100644
@@ -2132,6 +2132,9 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
 		vcpu->arch.interrupt.pending && !vcpu->arch.interrupt.soft;
 	events->interrupt.nr = vcpu->arch.interrupt.nr;
 	events->interrupt.soft = 0;
+	events->interrupt.shadow =
+		!!kvm_x86_ops->get_interrupt_shadow(vcpu,
+				X86_SHADOW_INT_MOV_SS | X86_SHADOW_INT_STI);
 
 	events->nmi.injected = vcpu->arch.nmi_injected;
 	events->nmi.pending = vcpu->arch.nmi_pending;
@@ -2140,7 +2143,8 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
 	events->sipi_vector = vcpu->arch.sipi_vector;
 
 	events->flags = (KVM_VCPUEVENT_VALID_NMI_PENDING
-			 | KVM_VCPUEVENT_VALID_SIPI_VECTOR);
+			 | KVM_VCPUEVENT_VALID_SIPI_VECTOR
+			 | KVM_VCPUEVENT_VALID_SHADOW);
 
 	vcpu_put(vcpu);
 }
@@ -2149,7 +2153,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
 					      struct kvm_vcpu_events *events)
 {
 	if (events->flags & ~(KVM_VCPUEVENT_VALID_NMI_PENDING
-			      | KVM_VCPUEVENT_VALID_SIPI_VECTOR))
+			      | KVM_VCPUEVENT_VALID_SIPI_VECTOR
+			      | KVM_VCPUEVENT_VALID_SHADOW))
 		return -EINVAL;
 
 	vcpu_load(vcpu);
@@ -2164,6 +2169,9 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
 	vcpu->arch.interrupt.soft = events->interrupt.soft;
 	if (vcpu->arch.interrupt.pending && irqchip_in_kernel(vcpu->kvm))
 		kvm_pic_clear_isr_ack(vcpu->kvm);
+	if (events->flags & KVM_VCPUEVENT_VALID_SHADOW)
+		kvm_x86_ops->set_interrupt_shadow(vcpu,
+			events->interrupt.shadow ? X86_SHADOW_INT_MOV_SS : 0);
 
 	vcpu->arch.nmi_injected = events->nmi.injected;
 	if (events->flags & KVM_VCPUEVENT_VALID_NMI_PENDING)
include/linux/kvm.h +1 -0
index dfa54be..46fb860 100644
@@ -501,6 +501,7 @@ struct kvm_ioeventfd {
 #define KVM_CAP_HYPERV_VAPIC 45
 #define KVM_CAP_HYPERV_SPIN 46
 #define KVM_CAP_PCI_SEGMENT 47
+#define KVM_CAP_INTR_SHADOW 48
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
Signature · 1 line
1.6.0.2
#3 lore raw

Re: [PATCH 2/3] KVM: x86: Save&restore interrupt shadow mask

Quoted 132 lines · Jan Kiszka

The interrupt shadow created by STI or MOV-SS-like operations is part of the VCPU state and must be preserved across migration. Transfer it in the spare padding field of kvm_vcpu_events.interrupt.

As a side effect we now have to make vmx_set_interrupt_shadow robust against both shadow types being set. Give MOV SS a higher priority and skip STI in that case to avoid that VMX throws a fault on next entry.

---
 Documentation/kvm/api.txt  |   11 ++++++++++-
 arch/x86/include/asm/kvm.h |    3 ++-
 arch/x86/kvm/vmx.c         |    2 +-
 arch/x86/kvm/x86.c         |   12 ++++++++++--
 include/linux/kvm.h        |    1 +
 5 files changed, 24 insertions(+), 5 deletions(-)
Documentation/kvm/api.txt +10 -1
index c6416a3..8770b67 100644
@@ -656,6 +656,7 @@ struct kvm_clock_data {
 4.29 KVM_GET_VCPU_EVENTS
 
 Capability: KVM_CAP_VCPU_EVENTS
+Extended by: KVM_CAP_INTR_SHADOW
 Architectures: x86
 Type: vm ioctl
 Parameters: struct kvm_vcpu_event (out)
@@ -676,7 +677,7 @@ struct kvm_vcpu_events {
 		__u8 injected;
 		__u8 nr;
 		__u8 soft;
-		__u8 pad;
+		__u8 shadow;
 	} interrupt;
 	struct {
 		__u8 injected;
@@ -688,9 +689,13 @@ struct kvm_vcpu_events {
 	__u32 flags;
 };
 
+KVM_VCPUEVENT_VALID_SHADOW may be set in the flags field to signal that
+interrupt.shadow contains a valid state. Otherwise, this field is undefined.
+
 4.30 KVM_SET_VCPU_EVENTS
 
 Capability: KVM_CAP_VCPU_EVENTS
+Extended by: KVM_CAP_INTR_SHADOW
 Architectures: x86
 Type: vm ioctl
 Parameters: struct kvm_vcpu_event (in)
@@ -709,6 +714,10 @@ current in-kernel state. The bits are:
 KVM_VCPUEVENT_VALID_NMI_PENDING - transfer nmi.pending to the kernel
 KVM_VCPUEVENT_VALID_SIPI_VECTOR - transfer sipi_vector
 
+If KVM_CAP_INTR_SHADOW is available, KVM_VCPUEVENT_VALID_SHADOW can be set in
+the flags field to signal that interrupt.shadow contains a valid state and
+shall be written into the VCPU.
+
 
 5. The kvm_run structure
 
arch/x86/include/asm/kvm.h +2 -1
index f46b79f..dc6cd24 100644
@@ -257,6 +257,7 @@ struct kvm_reinject_control {
 /* When set in flags, include corresponding fields on KVM_SET_VCPU_EVENTS */
 #define KVM_VCPUEVENT_VALID_NMI_PENDING	0x00000001
 #define KVM_VCPUEVENT_VALID_SIPI_VECTOR	0x00000002
+#define KVM_VCPUEVENT_VALID_SHADOW	0x00000004
 
 /* for KVM_GET/SET_VCPU_EVENTS */
 struct kvm_vcpu_events {
@@ -271,7 +272,7 @@ struct kvm_vcpu_events {
 		__u8 injected;
 		__u8 nr;
 		__u8 soft;
-		__u8 pad;
+		__u8 shadow;
 	} interrupt;
 	struct {
 		__u8 injected;
arch/x86/kvm/vmx.c +1 -1
index f82b072..0fa74d0 100644
@@ -854,7 +854,7 @@ static void vmx_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask)
 
 	if (mask & X86_SHADOW_INT_MOV_SS)
 		interruptibility |= GUEST_INTR_STATE_MOV_SS;
-	if (mask & X86_SHADOW_INT_STI)
+	else if (mask & X86_SHADOW_INT_STI)
 		interruptibility |= GUEST_INTR_STATE_STI;
 
 	if ((interruptibility != interruptibility_old))
arch/x86/kvm/x86.c +7 -2
index 50d1d2a..60e6341 100644
@@ -2132,6 +2132,9 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
 		vcpu->arch.interrupt.pending && !vcpu->arch.interrupt.soft;
 	events->interrupt.nr = vcpu->arch.interrupt.nr;
 	events->interrupt.soft = 0;
+	events->interrupt.shadow =
+		!!kvm_x86_ops->get_interrupt_shadow(vcpu,
+				X86_SHADOW_INT_MOV_SS | X86_SHADOW_INT_STI);
 
 	events->nmi.injected = vcpu->arch.nmi_injected;
 	events->nmi.pending = vcpu->arch.nmi_pending;
@@ -2140,7 +2143,8 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
 	events->sipi_vector = vcpu->arch.sipi_vector;
 
 	events->flags = (KVM_VCPUEVENT_VALID_NMI_PENDING
-			 | KVM_VCPUEVENT_VALID_SIPI_VECTOR);
+			 | KVM_VCPUEVENT_VALID_SIPI_VECTOR
+			 | KVM_VCPUEVENT_VALID_SHADOW);
 
 	vcpu_put(vcpu);
 }
@@ -2149,7 +2153,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
 					      struct kvm_vcpu_events *events)
 {
 	if (events->flags & ~(KVM_VCPUEVENT_VALID_NMI_PENDING
-			      | KVM_VCPUEVENT_VALID_SIPI_VECTOR))
+			      | KVM_VCPUEVENT_VALID_SIPI_VECTOR
+			      | KVM_VCPUEVENT_VALID_SHADOW))
 		return -EINVAL;
 
 	vcpu_load(vcpu);

arch/x86/kvm/x86.c static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, · line 2174

Quoted 6 lines
arch/x86/kvm/x86.c +3 -0
@@ -2164,6 +2169,9 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
 	vcpu->arch.interrupt.soft = events->interrupt.soft;
 	if (vcpu->arch.interrupt.pending && irqchip_in_kernel(vcpu->kvm))
 		kvm_pic_clear_isr_ack(vcpu->kvm);
+	if (events->flags & KVM_VCPUEVENT_VALID_SHADOW)
+		kvm_x86_ops->set_interrupt_shadow(vcpu,
+			events->interrupt.shadow ? X86_SHADOW_INT_MOV_SS : 0);

Its hackish to transform blocking-by-sti into blocking-by-mov-ss (sti does not block debug exceptions for the next instruction).

Any special reason you are doing this?

Also, as Avi mentioned it would be better to avoid this. Is it not possible to disallow migration while interrupt shadow is present?

#4 lore raw

Re: [PATCH 2/3] KVM: x86: Save&restore interrupt shadow mask

Quoted 5 lines · Marcelo Tosatti
Quoted 3 lines · Jan Kiszka

The interrupt shadow created by STI or MOV-SS-like operations is part of the VCPU state and must be preserved across migration. Transfer it in the spare padding field of kvm_vcpu_events.interrupt.

STI and MOV-SS interrupt shadow are both treated differently by hardware. Any attempt to unify them into a single field is wrong, especially so in a hardware virtualization context, where they are actually represented by different fields in the undocumented but nevertheless extant format that can be inferred from the hardware virtualization context used by specific vendors.

Zach

#5 lore raw

Re: [PATCH 2/3] KVM: x86: Save&restore interrupt shadow mask

Quoted 6 lines · Zachary Amsden
Quoted 4 lines · Marcelo Tosatti
Quoted 3 lines · Jan Kiszka

The interrupt shadow created by STI or MOV-SS-like operations is part of the VCPU state and must be preserved across migration. Transfer it in the spare padding field of kvm_vcpu_events.interrupt.

Quoted 7 lines

STI and MOV-SS interrupt shadow are both treated differently by hardware. Any attempt to unify them into a single field is wrong, especially so in a hardware virtualization context, where they are actually represented by different fields in the undocumented but nevertheless extant format that can be inferred from the hardware virtualization context used by specific vendors.

The problem is SVM doesn't distinguish between those two. But we shouldn't design out interfaces based on SVM brokenness.

--
Gleb.

author
#6 lore raw

Re: [PATCH 2/3] KVM: x86: Save&restore interrupt shadow mask

In reply to Zachary Amsden
Quoted 7 lines · Zachary Amsden
Quoted 5 lines · Marcelo Tosatti
Quoted 3 lines · Jan Kiszka

The interrupt shadow created by STI or MOV-SS-like operations is part of the VCPU state and must be preserved across migration. Transfer it in the spare padding field of kvm_vcpu_events.interrupt.

Quoted 6 lines

STI and MOV-SS interrupt shadow are both treated differently by hardware. Any attempt to unify them into a single field is wrong, especially so in a hardware virtualization context, where they are actually represented by different fields in the undocumented but nevertheless extant format that can be inferred from the hardware virtualization context used by specific vendors.

Someone should ask AMD why they thought differently about this while designing SVM...

Jan

Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux
author
#7 lore raw

Re: [PATCH 2/3] KVM: x86: Save&restore interrupt shadow mask

In reply to Marcelo Tosatti
Quoted 143 lines · Marcelo Tosatti
Quoted 132 lines · Jan Kiszka

The interrupt shadow created by STI or MOV-SS-like operations is part of the VCPU state and must be preserved across migration. Transfer it in the spare padding field of kvm_vcpu_events.interrupt.

As a side effect we now have to make vmx_set_interrupt_shadow robust against both shadow types being set. Give MOV SS a higher priority and skip STI in that case to avoid that VMX throws a fault on next entry.

---
 Documentation/kvm/api.txt  |   11 ++++++++++-
 arch/x86/include/asm/kvm.h |    3 ++-
 arch/x86/kvm/vmx.c         |    2 +-
 arch/x86/kvm/x86.c         |   12 ++++++++++--
 include/linux/kvm.h        |    1 +
 5 files changed, 24 insertions(+), 5 deletions(-)
Documentation/kvm/api.txt +10 -1
index c6416a3..8770b67 100644
@@ -656,6 +656,7 @@ struct kvm_clock_data {
 4.29 KVM_GET_VCPU_EVENTS
 
 Capability: KVM_CAP_VCPU_EVENTS
+Extended by: KVM_CAP_INTR_SHADOW
 Architectures: x86
 Type: vm ioctl
 Parameters: struct kvm_vcpu_event (out)
@@ -676,7 +677,7 @@ struct kvm_vcpu_events {
 		__u8 injected;
 		__u8 nr;
 		__u8 soft;
-		__u8 pad;
+		__u8 shadow;
 	} interrupt;
 	struct {
 		__u8 injected;
@@ -688,9 +689,13 @@ struct kvm_vcpu_events {
 	__u32 flags;
 };
 
+KVM_VCPUEVENT_VALID_SHADOW may be set in the flags field to signal that
+interrupt.shadow contains a valid state. Otherwise, this field is undefined.
+
 4.30 KVM_SET_VCPU_EVENTS
 
 Capability: KVM_CAP_VCPU_EVENTS
+Extended by: KVM_CAP_INTR_SHADOW
 Architectures: x86
 Type: vm ioctl
 Parameters: struct kvm_vcpu_event (in)
@@ -709,6 +714,10 @@ current in-kernel state. The bits are:
 KVM_VCPUEVENT_VALID_NMI_PENDING - transfer nmi.pending to the kernel
 KVM_VCPUEVENT_VALID_SIPI_VECTOR - transfer sipi_vector
 
+If KVM_CAP_INTR_SHADOW is available, KVM_VCPUEVENT_VALID_SHADOW can be set in
+the flags field to signal that interrupt.shadow contains a valid state and
+shall be written into the VCPU.
+
 
 5. The kvm_run structure
 
arch/x86/include/asm/kvm.h +2 -1
index f46b79f..dc6cd24 100644
@@ -257,6 +257,7 @@ struct kvm_reinject_control {
 /* When set in flags, include corresponding fields on KVM_SET_VCPU_EVENTS */
 #define KVM_VCPUEVENT_VALID_NMI_PENDING	0x00000001
 #define KVM_VCPUEVENT_VALID_SIPI_VECTOR	0x00000002
+#define KVM_VCPUEVENT_VALID_SHADOW	0x00000004
 
 /* for KVM_GET/SET_VCPU_EVENTS */
 struct kvm_vcpu_events {
@@ -271,7 +272,7 @@ struct kvm_vcpu_events {
 		__u8 injected;
 		__u8 nr;
 		__u8 soft;
-		__u8 pad;
+		__u8 shadow;
 	} interrupt;
 	struct {
 		__u8 injected;
arch/x86/kvm/vmx.c +1 -1
index f82b072..0fa74d0 100644
@@ -854,7 +854,7 @@ static void vmx_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask)
 
 	if (mask & X86_SHADOW_INT_MOV_SS)
 		interruptibility |= GUEST_INTR_STATE_MOV_SS;
-	if (mask & X86_SHADOW_INT_STI)
+	else if (mask & X86_SHADOW_INT_STI)
 		interruptibility |= GUEST_INTR_STATE_STI;
 
 	if ((interruptibility != interruptibility_old))
arch/x86/kvm/x86.c +7 -2
index 50d1d2a..60e6341 100644
@@ -2132,6 +2132,9 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
 		vcpu->arch.interrupt.pending && !vcpu->arch.interrupt.soft;
 	events->interrupt.nr = vcpu->arch.interrupt.nr;
 	events->interrupt.soft = 0;
+	events->interrupt.shadow =
+		!!kvm_x86_ops->get_interrupt_shadow(vcpu,
+				X86_SHADOW_INT_MOV_SS | X86_SHADOW_INT_STI);
 
 	events->nmi.injected = vcpu->arch.nmi_injected;
 	events->nmi.pending = vcpu->arch.nmi_pending;
@@ -2140,7 +2143,8 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
 	events->sipi_vector = vcpu->arch.sipi_vector;
 
 	events->flags = (KVM_VCPUEVENT_VALID_NMI_PENDING
-			 | KVM_VCPUEVENT_VALID_SIPI_VECTOR);
+			 | KVM_VCPUEVENT_VALID_SIPI_VECTOR
+			 | KVM_VCPUEVENT_VALID_SHADOW);
 
 	vcpu_put(vcpu);
 }
@@ -2149,7 +2153,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
 					      struct kvm_vcpu_events *events)
 {
 	if (events->flags & ~(KVM_VCPUEVENT_VALID_NMI_PENDING
-			      | KVM_VCPUEVENT_VALID_SIPI_VECTOR))
+			      | KVM_VCPUEVENT_VALID_SIPI_VECTOR
+			      | KVM_VCPUEVENT_VALID_SHADOW))
 		return -EINVAL;
 
 	vcpu_load(vcpu);

arch/x86/kvm/x86.c static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, · line 2174

Quoted 6 lines
arch/x86/kvm/x86.c +3 -0
@@ -2164,6 +2169,9 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
 	vcpu->arch.interrupt.soft = events->interrupt.soft;
 	if (vcpu->arch.interrupt.pending && irqchip_in_kernel(vcpu->kvm))
 		kvm_pic_clear_isr_ack(vcpu->kvm);
+	if (events->flags & KVM_VCPUEVENT_VALID_SHADOW)
+		kvm_x86_ops->set_interrupt_shadow(vcpu,
+			events->interrupt.shadow ? X86_SHADOW_INT_MOV_SS : 0);

Its hackish to transform blocking-by-sti into blocking-by-mov-ss (sti does not block debug exceptions for the next instruction).

Quoted 1 line

Any special reason you are doing this?

AMD makes no difference, so it would be automatically unified during cross-vendor migration.

Quoted 3 lines

Also, as Avi mentioned it would be better to avoid this. Is it not possible to disallow migration while interrupt shadow is present?

Which means disallowing user space exists while the shadow it set? Or should we introduce some flag for user space that tells it "do not migration now, resume the guest till next exit"?

Jan

Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux
#8 lore raw

Re: [PATCH 2/3] KVM: x86: Save&restore interrupt shadow mask

Quoted 8 lines · Jan Kiszka
Quoted 3 lines

Also, as Avi mentioned it would be better to avoid this. Is it not possible to disallow migration while interrupt shadow is present?

Which means disallowing user space exists while the shadow it set? Or should we introduce some flag for user space that tells it "do not migration now, resume the guest till next exit"?

I think disabling migration is a slippery slope. Guest may abuse it. May be it will be hard to do with interrupt shadow, but the mechanism will be used for other cases too. I remember there was an argument that we should not migrate while vcpu is in a nested guest mode.

--
Gleb.

#9 lore raw

Re: [PATCH 2/3] KVM: x86: Save&restore interrupt shadow mask

Quoted 5 lines · Gleb Natapov
Quoted 4 lines · Jan Kiszka
Quoted 3 lines

Also, as Avi mentioned it would be better to avoid this. Is it not possible to disallow migration while interrupt shadow is present?

Quoted 8 lines
Quoted 4 lines

Which means disallowing user space exists while the shadow it set? Or should we introduce some flag for user space that tells it "do not migration now, resume the guest till next exit"?

I think disabling migration is a slippery slope. Guest may abuse it. May be it will be hard to do with interrupt shadow, but the mechanism will be used for other cases too. I remember there was an argument that we should not migrate while vcpu is in a nested guest mode.

Agree that guest may abuse it. Better to save/restore blocking-by-sti/by-mov-ss individually.

I was thinking the writeback of interrupt shadow / interruptibility state would be too complicated (eg necessary to care about ordering, etc), but now i see its handled in kernel (inject_pending_event and friends).

author
#10 lore raw

PATCH v3 2/3 KVM: x86: Save&restore interrupt shadow mask

In reply to Jan Kiszka

The interrupt shadow created by STI or MOV-SS-like operations is part of the VCPU state and must be preserved across migration. Transfer it in the spare padding field of kvm_vcpu_events.interrupt.

As a side effect we now have to make vmx_set_interrupt_shadow robust against both shadow types being set. Give MOV SS a higher priority and skip STI in that case to avoid that VMX throws a fault on next entry.

---

Changes in v3 (aka "back to square #1"):
- export both MOV SS and STI shadows, do not collapse them

 Documentation/kvm/api.txt          |   11 ++++++++++-
 arch/x86/include/asm/kvm.h         |    7 ++++++-
 arch/x86/include/asm/kvm_emulate.h |    3 ---
 arch/x86/kvm/emulate.c             |    5 +++--
 arch/x86/kvm/svm.c                 |    2 +-
 arch/x86/kvm/vmx.c                 |    8 ++++----
 arch/x86/kvm/x86.c                 |   12 ++++++++++--
 include/linux/kvm.h                |    1 +
 8 files changed, 35 insertions(+), 14 deletions(-)
Documentation/kvm/api.txt +10 -1
index beb444a..9e5de5a 100644
@@ -656,6 +656,7 @@ struct kvm_clock_data {
 4.29 KVM_GET_VCPU_EVENTS
 
 Capability: KVM_CAP_VCPU_EVENTS
+Extended by: KVM_CAP_INTR_SHADOW
 Architectures: x86
 Type: vm ioctl
 Parameters: struct kvm_vcpu_event (out)
@@ -676,7 +677,7 @@ struct kvm_vcpu_events {
 		__u8 injected;
 		__u8 nr;
 		__u8 soft;
-		__u8 pad;
+		__u8 shadow;
 	} interrupt;
 	struct {
 		__u8 injected;
@@ -688,9 +689,13 @@ struct kvm_vcpu_events {
 	__u32 flags;
 };
 
+KVM_VCPUEVENT_VALID_SHADOW may be set in the flags field to signal that
+interrupt.shadow contains a valid state. Otherwise, this field is undefined.
+
 4.30 KVM_SET_VCPU_EVENTS
 
 Capability: KVM_CAP_VCPU_EVENTS
+Extended by: KVM_CAP_INTR_SHADOW
 Architectures: x86
 Type: vm ioctl
 Parameters: struct kvm_vcpu_event (in)
@@ -709,6 +714,10 @@ current in-kernel state. The bits are:
 KVM_VCPUEVENT_VALID_NMI_PENDING - transfer nmi.pending to the kernel
 KVM_VCPUEVENT_VALID_SIPI_VECTOR - transfer sipi_vector
 
+If KVM_CAP_INTR_SHADOW is available, KVM_VCPUEVENT_VALID_SHADOW can be set in
+the flags field to signal that interrupt.shadow contains a valid state and
+shall be written into the VCPU.
+
 
 5. The kvm_run structure
 
arch/x86/include/asm/kvm.h +6 -1
index f46b79f..fb61170 100644
@@ -257,6 +257,11 @@ struct kvm_reinject_control {
 /* When set in flags, include corresponding fields on KVM_SET_VCPU_EVENTS */
 #define KVM_VCPUEVENT_VALID_NMI_PENDING	0x00000001
 #define KVM_VCPUEVENT_VALID_SIPI_VECTOR	0x00000002
+#define KVM_VCPUEVENT_VALID_SHADOW	0x00000004
+
+/* Interrupt shadow states */
+#define KVM_X86_SHADOW_INT_MOV_SS	0x01
+#define KVM_X86_SHADOW_INT_STI		0x02
 
 /* for KVM_GET/SET_VCPU_EVENTS */
 struct kvm_vcpu_events {
@@ -271,7 +276,7 @@ struct kvm_vcpu_events {
 		__u8 injected;
 		__u8 nr;
 		__u8 soft;
-		__u8 pad;
+		__u8 shadow;
 	} interrupt;
 	struct {
 		__u8 injected;
arch/x86/include/asm/kvm_emulate.h +0 -3
index 7a6f54f..2666d7a 100644
@@ -153,9 +153,6 @@ struct decode_cache {
 	struct fetch_cache fetch;
 };
 
-#define X86_SHADOW_INT_MOV_SS  1
-#define X86_SHADOW_INT_STI     2
-
 struct x86_emulate_ctxt {
 	/* Register state before/after emulation. */
 	struct kvm_vcpu *vcpu;
arch/x86/kvm/emulate.c +3 -2
index 9beda8e..135bc56 100644
@@ -2123,7 +2123,8 @@ special_insn:
 
 		sel = c->src.val;
 		if (c->modrm_reg == VCPU_SREG_SS)
-			toggle_interruptibility(ctxt, X86_SHADOW_INT_MOV_SS);
+			toggle_interruptibility(ctxt,
+						KVM_X86_SHADOW_INT_MOV_SS);
 
 		if (c->modrm_reg <= 5) {
 			type_bits = (c->modrm_reg == 1) ? 9 : 1;
@@ -2374,7 +2375,7 @@ special_insn:
 		if (emulator_bad_iopl(ctxt))
 			kvm_inject_gp(ctxt->vcpu, 0);
 		else {
-			toggle_interruptibility(ctxt, X86_SHADOW_INT_STI);
+			toggle_interruptibility(ctxt, KVM_X86_SHADOW_INT_STI);
 			ctxt->eflags |= X86_EFLAGS_IF;
 			c->dst.type = OP_NONE;	/* Disable writeback. */
 		}
arch/x86/kvm/svm.c +1 -1
index 2e1e8d6..5f88a73 100644
@@ -263,7 +263,7 @@ static u32 svm_get_interrupt_shadow(struct kvm_vcpu *vcpu, int mask)
 	u32 ret = 0;
 
 	if (svm->vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK)
-		ret |= X86_SHADOW_INT_STI | X86_SHADOW_INT_MOV_SS;
+		ret |= KVM_X86_SHADOW_INT_STI | KVM_X86_SHADOW_INT_MOV_SS;
 	return ret & mask;
 }
 
arch/x86/kvm/vmx.c +4 -4
index f7c815b..ce5ec41 100644
@@ -838,9 +838,9 @@ static u32 vmx_get_interrupt_shadow(struct kvm_vcpu *vcpu, int mask)
 	int ret = 0;
 
 	if (interruptibility & GUEST_INTR_STATE_STI)
-		ret |= X86_SHADOW_INT_STI;
+		ret |= KVM_X86_SHADOW_INT_STI;
 	if (interruptibility & GUEST_INTR_STATE_MOV_SS)
-		ret |= X86_SHADOW_INT_MOV_SS;
+		ret |= KVM_X86_SHADOW_INT_MOV_SS;
 
 	return ret & mask;
 }
@@ -852,9 +852,9 @@ static void vmx_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask)
 
 	interruptibility &= ~(GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS);
 
-	if (mask & X86_SHADOW_INT_MOV_SS)
+	if (mask & KVM_X86_SHADOW_INT_MOV_SS)
 		interruptibility |= GUEST_INTR_STATE_MOV_SS;
-	if (mask & X86_SHADOW_INT_STI)
+	else if (mask & KVM_X86_SHADOW_INT_STI)
 		interruptibility |= GUEST_INTR_STATE_STI;
 
 	if ((interruptibility != interruptibility_old))
arch/x86/kvm/x86.c +10 -2
index d1b5024..9b13e15 100644
@@ -2132,6 +2132,9 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
 		vcpu->arch.interrupt.pending && !vcpu->arch.interrupt.soft;
 	events->interrupt.nr = vcpu->arch.interrupt.nr;
 	events->interrupt.soft = 0;
+	events->interrupt.shadow =
+		kvm_x86_ops->get_interrupt_shadow(vcpu,
+			KVM_X86_SHADOW_INT_MOV_SS | KVM_X86_SHADOW_INT_STI);
 
 	events->nmi.injected = vcpu->arch.nmi_injected;
 	events->nmi.pending = vcpu->arch.nmi_pending;
@@ -2140,7 +2143,8 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
 	events->sipi_vector = vcpu->arch.sipi_vector;
 
 	events->flags = (KVM_VCPUEVENT_VALID_NMI_PENDING
-			 | KVM_VCPUEVENT_VALID_SIPI_VECTOR);
+			 | KVM_VCPUEVENT_VALID_SIPI_VECTOR
+			 | KVM_VCPUEVENT_VALID_SHADOW);
 
 	vcpu_put(vcpu);
 }
@@ -2149,7 +2153,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
 					      struct kvm_vcpu_events *events)
 {
 	if (events->flags & ~(KVM_VCPUEVENT_VALID_NMI_PENDING
-			      | KVM_VCPUEVENT_VALID_SIPI_VECTOR))
+			      | KVM_VCPUEVENT_VALID_SIPI_VECTOR
+			      | KVM_VCPUEVENT_VALID_SHADOW))
 		return -EINVAL;
 
 	vcpu_load(vcpu);
@@ -2164,6 +2169,9 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
 	vcpu->arch.interrupt.soft = events->interrupt.soft;
 	if (vcpu->arch.interrupt.pending && irqchip_in_kernel(vcpu->kvm))
 		kvm_pic_clear_isr_ack(vcpu->kvm);
+	if (events->flags & KVM_VCPUEVENT_VALID_SHADOW)
+		kvm_x86_ops->set_interrupt_shadow(vcpu,
+						  events->interrupt.shadow);
 
 	vcpu->arch.nmi_injected = events->nmi.injected;
 	if (events->flags & KVM_VCPUEVENT_VALID_NMI_PENDING)
include/linux/kvm.h +1 -0
index dfa54be..46fb860 100644
@@ -501,6 +501,7 @@ struct kvm_ioeventfd {
 #define KVM_CAP_HYPERV_VAPIC 45
 #define KVM_CAP_HYPERV_SPIN 46
 #define KVM_CAP_PCI_SEGMENT 47
+#define KVM_CAP_INTR_SHADOW 48
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
author
#11 lore raw

PATCH 3/3 KVM: x86: Add support for saving&restoring debug registers

In reply to Jan Kiszka

So far user space was not able to save and restore debug registers for migration or after reset. Plug this hole.

---
 Documentation/kvm/api.txt  |   31 +++++++++++++++++++++++++
 arch/x86/include/asm/kvm.h |   10 ++++++++
 arch/x86/kvm/x86.c         |   54 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/kvm.h        |    6 +++++
 4 files changed, 101 insertions(+), 0 deletions(-)
Documentation/kvm/api.txt +31 -0
index 8770b67..6753158 100644
@@ -718,6 +718,37 @@ If KVM_CAP_INTR_SHADOW is available, KVM_VCPUEVENT_VALID_SHADOW can be set in
 the flags field to signal that interrupt.shadow contains a valid state and
 shall be written into the VCPU.
 
+4.32 KVM_GET_DEBUGREGS
+
+Capability: KVM_CAP_DEBUGREGS
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_debugregs (out)
+Returns: 0 on success, -1 on error
+
+Reads debug registers from the vcpu.
+
+struct kvm_debugregs {
+	__u64 db[4];
+	__u64 dr6;
+	__u64 dr7;
+	__u64 flags;
+	__u64 reserved[9];
+};
+
+4.33 KVM_SET_DEBUGREGS
+
+Capability: KVM_CAP_DEBUGREGS
+Architectures: x86
+Type: vm ioctl
+Parameters: struct kvm_debugregs (in)
+Returns: 0 on success, -1 on error
+
+Writes debug registers into the vcpu.
+
+See KVM_GET_DEBUGREGS for the data structure. The flags field is unused
+yet and must be cleared on entry.
+
 
 5. The kvm_run structure
 
arch/x86/include/asm/kvm.h +10 -0
index dc6cd24..a81920b 100644
@@ -21,6 +21,7 @@
 #define __KVM_HAVE_PIT_STATE2
 #define __KVM_HAVE_XEN_HVM
 #define __KVM_HAVE_VCPU_EVENTS
+#define __KVM_HAVE_DEBUGREGS
 
 /* Architectural interrupt line count. */
 #define KVM_NR_INTERRUPTS 256
@@ -285,4 +286,13 @@ struct kvm_vcpu_events {
 	__u32 reserved[10];
 };
 
+/* for KVM_GET/SET_DEBUGREGS */
+struct kvm_debugregs {
+	__u64 db[4];
+	__u64 dr6;
+	__u64 dr7;
+	__u64 flags;
+	__u64 reserved[9];
+};
+
 #endif /* _ASM_X86_KVM_H */
arch/x86/kvm/x86.c +54 -0

72 lines not on this page · raw message

include/linux/kvm.h +6 -0
index 46fb860..667aec5 100644
@@ -502,6 +502,9 @@ struct kvm_ioeventfd {
 #define KVM_CAP_HYPERV_SPIN 46
 #define KVM_CAP_PCI_SEGMENT 47
 #define KVM_CAP_INTR_SHADOW 48
+#ifdef __KVM_HAVE_DEBUGREGS
+#define KVM_CAP_DEBUGREGS 49
+#endif
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -688,6 +691,9 @@ struct kvm_clock_data {
 /* Available with KVM_CAP_VCPU_EVENTS */
 #define KVM_GET_VCPU_EVENTS       _IOR(KVMIO,  0x9f, struct kvm_vcpu_events)
 #define KVM_SET_VCPU_EVENTS       _IOW(KVMIO,  0xa0, struct kvm_vcpu_events)
+/* Available with KVM_CAP_DEBUGREGS */
+#define KVM_GET_DEBUGREGS         _IOR(KVMIO,  0xa1, struct kvm_debugregs)
+#define KVM_SET_DEBUGREGS         _IOW(KVMIO,  0xa2, struct kvm_debugregs)
 
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
 
Signature · 1 line
1.6.0.2
author
#12 lore raw
In reply to Jan Kiszka
Quoted 25 lines · Jan Kiszka

These patches do not technically depend on each other but overlap, so I'm pushing them now in a series.

Patch 1 is a repost. Patch 2 is reworked and comes with the following changes:

- expose only a boolean to user space, mapping it on X86_SHADOW_INT_MOV_SS during write
- do not move X86_SHADOW_INT_* flags around
- Signal capability via KVM_CAP_INTR_SHADOW and manage the new kvm_vcpu_events field via KVM_VCPUEVENT_VALID_SHADOW
- Update docs

Finally, patch 3 is new, plugging the debug register migration (and reset) hole.

You can also pull from

git://git.kiszka.org/linux-kvm vcpu-state

Jan Kiszka (3):
KVM: x86: Do not return soft events in vcpu_events
KVM: x86: Save&restore interrupt shadow mask
KVM: x86: Add support for saving&restoring debug registers

Quoted 7 lines
 Documentation/kvm/api.txt  |   42 ++++++++++++++++++++++++-
 arch/x86/include/asm/kvm.h |   13 +++++++-
 arch/x86/kvm/vmx.c         |    2 +-
 arch/x86/kvm/x86.c         |   75 +++++++++++++++++++++++++++++++++++++++++---
 include/linux/kvm.h        |    7 ++++
 5 files changed, 131 insertions(+), 8 deletions(-)

[Trying to sort my patch queues]

Ping on this series with updated patch 2. Any open issues remaining?

Jan

Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux
#13 lore raw
Quoted 5 lines · Jan Kiszka

[Trying to sort my patch queues]

Ping on this series with updated patch 2. Any open issues remaining?

My default algorithm on patches with a lot of noise is to wait until the dust settles. I'll look at it now.

Signature · 1 line
error compiling committee.c: too many arguments to function
#14 lore raw
Quoted 8 lines · Avi Kivity
Quoted 4 lines · Jan Kiszka

[Trying to sort my patch queues]

Ping on this series with updated patch 2. Any open issues remaining?

My default algorithm on patches with a lot of noise is to wait until the dust settles. I'll look at it now.

All applied.

Signature · 1 line
error compiling committee.c: too many arguments to function