diff options
author | Nadav Amit <namit@cs.technion.ac.il> | 2014-06-18 10:19:26 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2014-06-19 06:52:15 -0400 |
commit | 27e6fb5dae2819d17f38dc9224692b771e989981 (patch) | |
tree | a70eb57477af54459b6d97f9e34156eaf01ed6b2 /arch | |
parent | 1e32c07955b43e7f827174bf320ed35971117275 (diff) |
KVM: vmx: vmx instructions handling does not consider cs.l
VMX instructions use 32-bit operands in 32-bit mode, and 64-bit operands in
64-bit mode. The current implementation is broken since it does not use the
register operands correctly, and always uses 64-bit for reads and writes.
Moreover, write to memory in vmwrite only considers long-mode, so it ignores
cs.l. This patch fixes this behavior.
Signed-off-by: Nadav Amit <namit@cs.technion.ac.il>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kvm/vmx.c | 12 | ||||
-rw-r--r-- | arch/x86/kvm/x86.h | 9 |
2 files changed, 15 insertions, 6 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 45024bf0e229..8748c2e19ed6 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -6403,7 +6403,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu) | |||
6403 | return 1; | 6403 | return 1; |
6404 | 6404 | ||
6405 | /* Decode instruction info and find the field to read */ | 6405 | /* Decode instruction info and find the field to read */ |
6406 | field = kvm_register_read(vcpu, (((vmx_instruction_info) >> 28) & 0xf)); | 6406 | field = kvm_register_readl(vcpu, (((vmx_instruction_info) >> 28) & 0xf)); |
6407 | /* Read the field, zero-extended to a u64 field_value */ | 6407 | /* Read the field, zero-extended to a u64 field_value */ |
6408 | if (!vmcs12_read_any(vcpu, field, &field_value)) { | 6408 | if (!vmcs12_read_any(vcpu, field, &field_value)) { |
6409 | nested_vmx_failValid(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT); | 6409 | nested_vmx_failValid(vcpu, VMXERR_UNSUPPORTED_VMCS_COMPONENT); |
@@ -6416,7 +6416,7 @@ static int handle_vmread(struct kvm_vcpu *vcpu) | |||
6416 | * on the guest's mode (32 or 64 bit), not on the given field's length. | 6416 | * on the guest's mode (32 or 64 bit), not on the given field's length. |
6417 | */ | 6417 | */ |
6418 | if (vmx_instruction_info & (1u << 10)) { | 6418 | if (vmx_instruction_info & (1u << 10)) { |
6419 | kvm_register_write(vcpu, (((vmx_instruction_info) >> 3) & 0xf), | 6419 | kvm_register_writel(vcpu, (((vmx_instruction_info) >> 3) & 0xf), |
6420 | field_value); | 6420 | field_value); |
6421 | } else { | 6421 | } else { |
6422 | if (get_vmx_mem_address(vcpu, exit_qualification, | 6422 | if (get_vmx_mem_address(vcpu, exit_qualification, |
@@ -6453,21 +6453,21 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu) | |||
6453 | return 1; | 6453 | return 1; |
6454 | 6454 | ||
6455 | if (vmx_instruction_info & (1u << 10)) | 6455 | if (vmx_instruction_info & (1u << 10)) |
6456 | field_value = kvm_register_read(vcpu, | 6456 | field_value = kvm_register_readl(vcpu, |
6457 | (((vmx_instruction_info) >> 3) & 0xf)); | 6457 | (((vmx_instruction_info) >> 3) & 0xf)); |
6458 | else { | 6458 | else { |
6459 | if (get_vmx_mem_address(vcpu, exit_qualification, | 6459 | if (get_vmx_mem_address(vcpu, exit_qualification, |
6460 | vmx_instruction_info, &gva)) | 6460 | vmx_instruction_info, &gva)) |
6461 | return 1; | 6461 | return 1; |
6462 | if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, | 6462 | if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, |
6463 | &field_value, (is_long_mode(vcpu) ? 8 : 4), &e)) { | 6463 | &field_value, (is_64_bit_mode(vcpu) ? 8 : 4), &e)) { |
6464 | kvm_inject_page_fault(vcpu, &e); | 6464 | kvm_inject_page_fault(vcpu, &e); |
6465 | return 1; | 6465 | return 1; |
6466 | } | 6466 | } |
6467 | } | 6467 | } |
6468 | 6468 | ||
6469 | 6469 | ||
6470 | field = kvm_register_read(vcpu, (((vmx_instruction_info) >> 28) & 0xf)); | 6470 | field = kvm_register_readl(vcpu, (((vmx_instruction_info) >> 28) & 0xf)); |
6471 | if (vmcs_field_readonly(field)) { | 6471 | if (vmcs_field_readonly(field)) { |
6472 | nested_vmx_failValid(vcpu, | 6472 | nested_vmx_failValid(vcpu, |
6473 | VMXERR_VMWRITE_READ_ONLY_VMCS_COMPONENT); | 6473 | VMXERR_VMWRITE_READ_ONLY_VMCS_COMPONENT); |
@@ -6590,7 +6590,7 @@ static int handle_invept(struct kvm_vcpu *vcpu) | |||
6590 | } | 6590 | } |
6591 | 6591 | ||
6592 | vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO); | 6592 | vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO); |
6593 | type = kvm_register_read(vcpu, (vmx_instruction_info >> 28) & 0xf); | 6593 | type = kvm_register_readl(vcpu, (vmx_instruction_info >> 28) & 0xf); |
6594 | 6594 | ||
6595 | types = (nested_vmx_ept_caps >> VMX_EPT_EXTENT_SHIFT) & 6; | 6595 | types = (nested_vmx_ept_caps >> VMX_EPT_EXTENT_SHIFT) & 6; |
6596 | 6596 | ||
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index c5b61a7eb144..306a1b77581f 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h | |||
@@ -126,6 +126,15 @@ static inline unsigned long kvm_register_readl(struct kvm_vcpu *vcpu, | |||
126 | return is_64_bit_mode(vcpu) ? val : (u32)val; | 126 | return is_64_bit_mode(vcpu) ? val : (u32)val; |
127 | } | 127 | } |
128 | 128 | ||
129 | static inline void kvm_register_writel(struct kvm_vcpu *vcpu, | ||
130 | enum kvm_reg reg, | ||
131 | unsigned long val) | ||
132 | { | ||
133 | if (!is_64_bit_mode(vcpu)) | ||
134 | val = (u32)val; | ||
135 | return kvm_register_write(vcpu, reg, val); | ||
136 | } | ||
137 | |||
129 | void kvm_before_handle_nmi(struct kvm_vcpu *vcpu); | 138 | void kvm_before_handle_nmi(struct kvm_vcpu *vcpu); |
130 | void kvm_after_handle_nmi(struct kvm_vcpu *vcpu); | 139 | void kvm_after_handle_nmi(struct kvm_vcpu *vcpu); |
131 | int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip); | 140 | int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip); |