KVM: x86: Add instruction length to VCPU event state
Subsystems (4)
PATCH 1/1 KVM: x86: Add instruction length to VCPU event state
From: Jan Kiszka <[email protected]>
VMX requires a properly set instruction length VM entry field when trying to inject soft exception and interrupts. We have to preserve this state across VM save/restore to avoid breaking the re-injection of such events on Intel. So add it to the new VCPU event state.
---
Existing qemu[-kvm]-0.12 that is already prepared for 2.6.33 will need an update now. Whenever we actually ran into the case that event_exit_inst_len was evaluated by VMX, we were playing roulette with a high probability to crash the guest. This will not changes for already released 0.12.x versions.
Documentation/kvm/api.txt | 2 ++ arch/x86/include/asm/kvm.h | 3 ++- arch/x86/kvm/x86.c | 4 ++++ 3 files changed, 8 insertions(+), 1 deletions(-)
Documentation/kvm/api.txt +2 -0
@@ -686,6 +686,8 @@ struct kvm_vcpu_events { } nmi; __u32 sipi_vector; __u32 flags; + __u32 instruction_length; /* used by VMX */ + __u32 reserved[9]; }; 4.30 KVM_SET_VCPU_EVENTS
arch/x86/include/asm/kvm.h +2 -1
@@ -281,7 +281,8 @@ struct kvm_vcpu_events { } nmi;__u32 sipi_vector;__u32 flags; -__u32 reserved[10 ]; +__u32 instruction_length;/* used by VMX */ +__u32 reserved[9 ]; };#endif /* _ASM_X86_KVM_H */
arch/x86/kvm/x86.c +4 -0
@@ -2134,6 +2134,8 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu, events->nmi.pending = vcpu->arch.nmi_pending; events->nmi.masked = kvm_x86_ops->get_nmi_mask (vcpu); + events->instruction_length = vcpu->arch.event_exit_inst_len; + events->sipi_vector = vcpu->arch.sipi_vector; events->flags = (KVM_VCPUEVENT_VALID_NMI_PENDING
@@ -2170,6 +2172,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,if (events->flags &KVM_VCPUEVENT_VALID_SIPI_VECTOR ) vcpu->arch.sipi_vector = events->sipi_vector; + vcpu->arch.event_exit_inst_len = events->instruction_length; +vcpu_put (vcpu);return 0 ;
Quoted 8 lines · Jan Kiszka
From: Jan Kiszka<[email protected]>
VMX requires a properly set instruction length VM entry field when trying to inject soft exception and interrupts. We have to preserve this state across VM save/restore to avoid breaking the re-injection of such events on Intel. So add it to the new VCPU event state.
Can't we fake it? set instruction length to 1 and rewind rip by 1.
The only case where I think this can fail is if we have a fault during the soft exception injection.
Signature · 1 line
Do not meddle in the internals of kernels, for they are subtle and quick to panic.
Quoted 10 lines · Avi Kivity
Quoted 8 lines · Jan Kiszka
From: Jan Kiszka<[email protected]>
VMX requires a properly set instruction length VM entry field when trying to inject soft exception and interrupts. We have to preserve this state across VM save/restore to avoid breaking the re-injection of such events on Intel. So add it to the new VCPU event state.
Quoted 4 lines
Can't we fake it? set instruction length to 1 and rewind rip by 1.
The only case where I think this can fail is if we have a fault during the soft exception injection.
I don't think so. If e.g. privileged soft exception delivery failed, we happen to return to user space at this point and we then start a migration, we have to deal with arbitrary lengths on re-injection on the migration target.
Jan
Quoted 7 lines · Jan Kiszka
From: Jan Kiszka <[email protected]>
VMX requires a properly set instruction length VM entry field when trying to inject soft exception and interrupts. We have to preserve this state across VM save/restore to avoid breaking the re-injection of such events on Intel. So add it to the new VCPU event state.
We shouldn't re-inject soft exceptions/interrupts after migration, but re-execute instruction instead. Instruction length field doesn't exist on SVM and migration shouldn't expose implementation details.
Quoted 56 lines
Signed-off-by Jan Kiszka <[email protected]>---
Existing qemu[-kvm]-0.12 that is already prepared for 2.6.33 will need an update now. Whenever we actually ran into the case that
event_exit_inst_lenwas evaluated by VMX, we were playing roulette with a high probability to crash the guest. This will not changes for already released 0.12.x versions.Documentation/kvm/api.txt | 2 ++ arch/x86/include/asm/kvm.h | 3 ++- arch/x86/kvm/x86.c | 4 ++++ 3 files changed, 8 insertions(+), 1 deletions(-)Documentation/kvm/api.txt +2
-0@@ -686,6 +686,8 @@ struct kvm_vcpu_events { } nmi; __u32 sipi_vector; __u32 flags; + __u32 instruction_length; /* used by VMX */ + __u32 reserved[9]; }; 4.30 KVM_SET_VCPU_EVENTSarch/x86/include/asm/kvm.h +2
-1@@ -281,7 +281,8 @@ struct kvm_vcpu_events { } nmi;__u32 sipi_vector;__u32 flags; -__u32 reserved[10 ]; +__u32 instruction_length;/* used by VMX */ +__u32 reserved[9 ]; };#endif /* _ASM_X86_KVM_H */ arch/x86/kvm/x86.c +2
-0@@ -2134,6 +2134,8 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu, events->nmi.pending = vcpu->arch.nmi_pending; events->nmi.masked = kvm_x86_ops->get_nmi_mask (vcpu); + events->instruction_length = vcpu->arch.event_exit_inst_len; + events->sipi_vector = vcpu->arch.sipi_vector; events->flags = (KVM_VCPUEVENT_VALID_NMI_PENDING
arch/x86/kvm/x86.c static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, · line 2179
Quoted 8 lines
arch/x86/kvm/x86.c +2
-0@@ -2170,6 +2172,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,if (events->flags &KVM_VCPUEVENT_VALID_SIPI_VECTOR ) vcpu->arch.sipi_vector = events->sipi_vector; + vcpu->arch.event_exit_inst_len = events->instruction_length; +vcpu_put (vcpu);return 0 ;
--
Gleb.
Quoted 12 lines · Gleb Natapov
Quoted 7 lines · Jan Kiszka
From: Jan Kiszka <[email protected]>
VMX requires a properly set instruction length VM entry field when trying to inject soft exception and interrupts. We have to preserve this state across VM save/restore to avoid breaking the re-injection of such events on Intel. So add it to the new VCPU event state.
We shouldn't re-inject soft exceptions/interrupts after migration, but re-execute instruction instead. Instruction length field doesn't exist on SVM and migration shouldn't expose implementation details.
Hmm, then I guess this totally untested patch should fly:
arch/x86/include/asm/kvm_host.h +0 -2
@@ -315,8 +315,6 @@ struct kvm_vcpu_arch {struct kvm_pio_request pio;void *pio_data; -u8 event_exit_inst_len; -struct kvm_queued_exception {bool pending;bool has_error_code;
arch/x86/kvm/vmx.c +4 -14
@@ -889,8 +889,7 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, vmx->rmode.irq.vector = nr; vmx->rmode.irq.rip =kvm_rip_read (vcpu);if (kvm_exception_is_soft (nr)) - vmx->rmode.irq.rip += - vmx->vcpu.arch.event_exit_inst_len; + vmx->rmode.irq.rip++; intr_info |=INTR_TYPE_SOFT_INTR ;vmcs_write32 (VM_ENTRY_INTR_INFO_FIELD , intr_info);vmcs_write32 (VM_ENTRY_INSTRUCTION_LEN ,1 );
@@ -899,8 +898,7 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr, }if (kvm_exception_is_soft (nr)) { -vmcs_write32 (VM_ENTRY_INSTRUCTION_LEN , - vmx->vcpu.arch.event_exit_inst_len); +vmcs_write32 (VM_ENTRY_INSTRUCTION_LEN ,1 ); intr_info |=INTR_TYPE_SOFT_EXCEPTION ; }else intr_info |=INTR_TYPE_HARD_EXCEPTION ;
@@ -2639,8 +2637,7 @@ static void vmx_inject_irq(struct kvm_vcpu *vcpu) vmx->rmode.irq.vector = irq; vmx->rmode.irq.rip =kvm_rip_read (vcpu);if (vcpu->arch.interrupt.soft) - vmx->rmode.irq.rip += - vmx->vcpu.arch.event_exit_inst_len; + vmx->rmode.irq.rip +=2 ;vmcs_write32 (VM_ENTRY_INTR_INFO_FIELD , irq |INTR_TYPE_SOFT_INTR |INTR_INFO_VALID_MASK );vmcs_write32 (VM_ENTRY_INSTRUCTION_LEN ,1 );
@@ -2650,8 +2647,7 @@ static void vmx_inject_irq(struct kvm_vcpu *vcpu) intr = irq |INTR_INFO_VALID_MASK ;if (vcpu->arch.interrupt.soft) { intr |=INTR_TYPE_SOFT_INTR ; -vmcs_write32 (VM_ENTRY_INSTRUCTION_LEN , - vmx->vcpu.arch.event_exit_inst_len); +vmcs_write32 (VM_ENTRY_INSTRUCTION_LEN ,2 ); }else intr |=INTR_TYPE_EXT_INTR ;vmcs_write32 (VM_ENTRY_INTR_INFO_FIELD , intr);
@@ -3688,9 +3684,6 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx) GUEST_INTR_STATE_NMI);break ;case INTR_TYPE_SOFT_EXCEPTION : - vmx->vcpu.arch.event_exit_inst_len = -vmcs_read32 (VM_EXIT_INSTRUCTION_LEN ); -/* fall through */ case INTR_TYPE_HARD_EXCEPTION :if (idt_vectoring_info &VECTORING_INFO_DELIVER_CODE_MASK ) {u32 err =vmcs_read32 (IDT_VECTORING_ERROR_CODE );
@@ -3699,9 +3692,6 @@ static void vmx_complete_interrupts(struct vcpu_vmx *vmx)kvm_queue_exception (&vmx->vcpu, vector);break ;case INTR_TYPE_SOFT_INTR : - vmx->vcpu.arch.event_exit_inst_len = -vmcs_read32 (VM_EXIT_INSTRUCTION_LEN ); -/* fall through */ case INTR_TYPE_EXT_INTR :kvm_queue_interrupt (&vmx->vcpu, vector, type ==INTR_TYPE_SOFT_INTR );
As we actually do not support privileged soft exceptions, we are left with int3 and into as single-byte instructions triggering soft exceptions and int N as a two-byte instruction a the reason for soft interrupts. Am I missing something?
Jan
Quoted 9 lines · Jan Kiszka
Quoted 8 lines · Gleb Natapov
Quoted 7 lines · Jan Kiszka
From: Jan Kiszka <[email protected]>
VMX requires a properly set instruction length VM entry field when trying to inject soft exception and interrupts. We have to preserve this state across VM save/restore to avoid breaking the re-injection of such events on Intel. So add it to the new VCPU event state.
Quoted 7 lines
Quoted 4 lines
We shouldn't re-inject soft exceptions/interrupts after migration, but re-execute instruction instead. Instruction length field doesn't exist on SVM and migration shouldn't expose implementation details.
Hmm, then I guess this totally untested patch should fly:
I don't understand what problem are you trying to solve by your patch. During normal operation event_exit_inst_len will be set to correct value. After migration rip will point to int instruction an no even will be pending at all. Here is the patch:
arch/x86/kvm/x86.c +12 -8
@@ -2121,14 +2121,18 @@ 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.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.nr = vcpu->arch.interrupt.nr; - events->interrupt.soft = vcpu->arch.interrupt.soft; +if (!kvm_exception_is_soft (nr)) { + events->exception.injected = vcpu->arch.exception.pending; + 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; + } + +if (!events->interrupt.soft) { + events->interrupt.injected = vcpu->arch.interrupt.pending; + events->interrupt.nr = vcpu->arch.interrupt.nr; + events->interrupt.soft = vcpu->arch.interrupt.soft; + } events->nmi.injected = vcpu->arch.nmi_injected; events->nmi.pending = vcpu->arch.nmi_pending;
--
Gleb.
Quoted 14 lines · Gleb Natapov
Quoted 13 lines · Jan Kiszka
Quoted 12 lines · Gleb Natapov
Quoted 7 lines · Jan Kiszka
From: Jan Kiszka <[email protected]>
VMX requires a properly set instruction length VM entry field when trying to inject soft exception and interrupts. We have to preserve this state across VM save/restore to avoid breaking the re-injection of such events on Intel. So add it to the new VCPU event state.
We shouldn't re-inject soft exceptions/interrupts after migration, but re-execute instruction instead. Instruction length field doesn't exist on SVM and migration shouldn't expose implementation details.
Quoted 6 lines
Quoted 2 lines
Hmm, then I guess this totally untested patch should fly:
I don't understand what problem are you trying to solve by your patch. During normal operation
event_exit_inst_lenwill be set to correct value. After migration rip will point to int instruction an no even will be pending at all. Here is the patch:
The patch will cause an endless loop if BP interception is enabled.
What is the purpose of keeping event_exit_inst_len around? Either we need it also across user space exists, then we have to save/restore or reconstruct it, or we don't need it, then simply drop it.
Jan
Quoted 15 lines · Jan Kiszka
Quoted 14 lines · Gleb Natapov
Quoted 13 lines · Jan Kiszka
Quoted 12 lines · Gleb Natapov
Quoted 7 lines · Jan Kiszka
From: Jan Kiszka <[email protected]>
VMX requires a properly set instruction length VM entry field when trying to inject soft exception and interrupts. We have to preserve this state across VM save/restore to avoid breaking the re-injection of such events on Intel. So add it to the new VCPU event state.
We shouldn't re-inject soft exceptions/interrupts after migration, but re-execute instruction instead. Instruction length field doesn't exist on SVM and migration shouldn't expose implementation details.
Quoted 9 lines
Quoted 6 lines
Quoted 2 lines
Hmm, then I guess this totally untested patch should fly:
I don't understand what problem are you trying to solve by your patch. During normal operation
event_exit_inst_lenwill be set to correct value. After migration rip will point to int instruction an no even will be pending at all. Here is the patch:The patch will cause an endless loop if BP interception is enabled.
How? This code path is not executed normally.
Quoted 4 lines
What is the purpose of keeping
event_exit_inst_lenaround? Either we need it also across user space exists, then we have to save/restore or reconstruct it, or we don't need it, then simply drop it.
Why we need to save/restore is if we need it across user space exits? We need to save/restore it only if we nedd it across migration.
When exception happens during soft interrupt/exception delivery soft i/e should be retried somehow. There are two ways to do that. First one is just reenter guest with the same rip. Instruction will be reexecuted and event redelivered. Another is to reinject event via event reinjection mechanism and for that we need to tell CPU how to calculate rip of a next instruction and this is done by providing event_exit_inst_len. The problem is that SVM supports only the first way. Intel advised us to use reinjection mechanism, so that what we use on VMX, but since migration can happen from Intel to AMD and vice versa we chose to reexecute instruction after migration on those rare occasions that migration happens exactly after intercepted soft i/e.
--
Gleb.
Quoted 18 lines · Gleb Natapov
Quoted 17 lines · Jan Kiszka
Quoted 16 lines · Gleb Natapov
Quoted 15 lines · Jan Kiszka
Quoted 12 lines · Gleb Natapov
Quoted 7 lines · Jan Kiszka
From: Jan Kiszka <[email protected]>
VMX requires a properly set instruction length VM entry field when trying to inject soft exception and interrupts. We have to preserve this state across VM save/restore to avoid breaking the re-injection of such events on Intel. So add it to the new VCPU event state.
We shouldn't re-inject soft exceptions/interrupts after migration, but re-execute instruction instead. Instruction length field doesn't exist on SVM and migration shouldn't expose implementation details.
Hmm, then I guess this totally untested patch should fly:
Quoted 7 lines
Quoted 6 lines
Quoted 4 lines
I don't understand what problem are you trying to solve by your patch. During normal operation
event_exit_inst_lenwill be set to correct value. After migration rip will point to int instruction an no even will be pending at all. Here is the patch:The patch will cause an endless loop if BP interception is enabled.
How? This code path is not executed normally.
Oh, I read it the other way around, but it is supposed to mask soft exceptions/irqs (clearing *.injected is missing then).
Quoted 8 lines
Quoted 5 lines
What is the purpose of keeping
event_exit_inst_lenaround? Either we need it also across user space exists, then we have to save/restore or reconstruct it, or we don't need it, then simply drop it.Why we need to save/restore is if we need it across user space exits? We need to save/restore it only if we nedd it across migration.
Quoted 6 lines
When exception happens during soft interrupt/exception delivery soft i/e should be retried somehow. There are two ways to do that. First one is just reenter guest with the same rip. Instruction will be reexecuted and event redelivered. Another is to reinject event via event reinjection mechanism and for that we need to tell CPU how to calculate rip of a next instruction and this is done by providing
event_exit_inst_len. The
But I still fail to see the case where event_exit_inst_len is set to anything but 1 or 2 and where it is related to anything else than exits at INT3, INT X, or INTO.
Quoted 5 lines
problem is that SVM supports only the first way. Intel advised us to use reinjection mechanism, so that what we use on VMX, but since migration can happen from Intel to AMD and vice versa we chose to reexecute instruction after migration on those rare occasions that migration happens exactly after intercepted soft i/e.
Jan
Quoted 45 lines · Jan Kiszka
Quoted 18 lines · Gleb Natapov
Quoted 17 lines · Jan Kiszka
Quoted 16 lines · Gleb Natapov
Quoted 15 lines · Jan Kiszka
Quoted 12 lines · Gleb Natapov
Quoted 7 lines · Jan Kiszka
From: Jan Kiszka <[email protected]>
VMX requires a properly set instruction length VM entry field when trying to inject soft exception and interrupts. We have to preserve this state across VM save/restore to avoid breaking the re-injection of such events on Intel. So add it to the new VCPU event state.
We shouldn't re-inject soft exceptions/interrupts after migration, but re-execute instruction instead. Instruction length field doesn't exist on SVM and migration shouldn't expose implementation details.
Hmm, then I guess this totally untested patch should fly:
Quoted 7 lines
Quoted 6 lines
Quoted 4 lines
I don't understand what problem are you trying to solve by your patch. During normal operation
event_exit_inst_lenwill be set to correct value. After migration rip will point to int instruction an no even will be pending at all. Here is the patch:The patch will cause an endless loop if BP interception is enabled.
How? This code path is not executed normally.
Oh, I read it the other way around, but it is supposed to mask soft exceptions/irqs (clearing *.injected is missing then).
Quoted 8 lines
Quoted 5 lines
What is the purpose of keeping
event_exit_inst_lenaround? Either we need it also across user space exists, then we have to save/restore or reconstruct it, or we don't need it, then simply drop it.Why we need to save/restore is if we need it across user space exits? We need to save/restore it only if we nedd it across migration.
Quoted 6 lines
When exception happens during soft interrupt/exception delivery soft i/e should be retried somehow. There are two ways to do that. First one is just reenter guest with the same rip. Instruction will be reexecuted and event redelivered. Another is to reinject event via event reinjection mechanism and for that we need to tell CPU how to calculate rip of a next instruction and this is done by providing
event_exit_inst_len. The
Quoted 4 lines
But I still fail to see the case where
event_exit_inst_lenis set to anything but 1 or 2 and where it is related to anything else than exits at INT3, INT X, or INTO.
You can't know real instruction length without decoding it or relying on VMX exit info. What if prefix were used for INT X?
Quoted 8 lines
Quoted 5 lines
problem is that SVM supports only the first way. Intel advised us to use reinjection mechanism, so that what we use on VMX, but since migration can happen from Intel to AMD and vice versa we chose to reexecute instruction after migration on those rare occasions that migration happens exactly after intercepted soft i/e.
Jan
--
Gleb.
Quoted 43 lines · Gleb Natapov
Quoted 42 lines · Jan Kiszka
Quoted 18 lines · Gleb Natapov
Quoted 17 lines · Jan Kiszka
Quoted 16 lines · Gleb Natapov
Quoted 15 lines · Jan Kiszka
Quoted 12 lines · Gleb Natapov
Quoted 7 lines · Jan Kiszka
From: Jan Kiszka <[email protected]>
VMX requires a properly set instruction length VM entry field when trying to inject soft exception and interrupts. We have to preserve this state across VM save/restore to avoid breaking the re-injection of such events on Intel. So add it to the new VCPU event state.
We shouldn't re-inject soft exceptions/interrupts after migration, but re-execute instruction instead. Instruction length field doesn't exist on SVM and migration shouldn't expose implementation details.
Hmm, then I guess this totally untested patch should fly:
Quoted 7 lines
Quoted 6 lines
Quoted 4 lines
I don't understand what problem are you trying to solve by your patch. During normal operation
event_exit_inst_lenwill be set to correct value. After migration rip will point to int instruction an no even will be pending at all. Here is the patch:The patch will cause an endless loop if BP interception is enabled.
How? This code path is not executed normally.
Oh, I read it the other way around, but it is supposed to mask soft exceptions/irqs (clearing *.injected is missing then).
Quoted 13 lines
Quoted 4 lines
What is the purpose of keeping
event_exit_inst_lenaround? Either we need it also across user space exists, then we have to save/restore or reconstruct it, or we don't need it, then simply drop it.Why we need to save/restore is if we need it across user space exits? We need to save/restore it only if we nedd it across migration.
When exception happens during soft interrupt/exception delivery soft i/e should be retried somehow. There are two ways to do that. First one is just reenter guest with the same rip. Instruction will be reexecuted and event redelivered. Another is to reinject event via event reinjection mechanism and for that we need to tell CPU how to calculate rip of a next instruction and this is done by providing
event_exit_inst_len. The
Quoted 7 lines
Quoted 4 lines
But I still fail to see the case where
event_exit_inst_lenis set to anything but 1 or 2 and where it is related to anything else than exits at INT3, INT X, or INTO.You can't know real instruction length without decoding it or relying on VMX exit info. What if prefix were used for INT X?
OK, makes sense now. Then let's go with your suggestion, will post it as a patch.
Thanks for explaining,
Jan
Paolo Bonzini
maintainerQuoted 3 lines · Jan Kiszka
But I still fail to see the case where
event_exit_inst_lenis set to anything but 1 or 2 and where it is related to anything else than exits at INT3, INT X, or INTO.
What about BOUND? (I want to hide for suggesting anyone uses that instruction).
Paolo
Quoted 8 lines · Paolo Bonzini
Quoted 3 lines · Jan Kiszka
But I still fail to see the case where
event_exit_inst_lenis set to anything but 1 or 2 and where it is related to anything else than exits at INT3, INT X, or INTO.What about BOUND? (I want to hide for suggesting anyone uses that instruction).
It is fault not a trap IIRC.
--
Gleb.
Quoted 6 lines · Paolo Bonzini
Quoted 3 lines · Jan Kiszka
But I still fail to see the case where
event_exit_inst_lenis set to anything but 1 or 2 and where it is related to anything else than exits at INT3, INT X, or INTO.What about BOUND? (I want to hide for suggesting anyone uses that instruction).
If compilers used it, software would run slower, but buffer overflows would be much rarer.
Signature · 1 line
error compiling committee.c: too many arguments to function