diff options
author | Nadav Har'El <nyh@il.ibm.com> | 2011-05-25 16:06:59 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2011-07-12 04:45:12 -0400 |
commit | 27d6c865211662721e6cf305706e4a3da35f12b4 (patch) | |
tree | 8ddad7953792e3ff0148e952dc9747db6a1b6305 /arch/x86/kvm | |
parent | 0140caea3b9972f826416a796271f17b42cbe827 (diff) |
KVM: nVMX: Implement VMCLEAR
This patch implements the VMCLEAR instruction.
Signed-off-by: Nadav Har'El <nyh@il.ibm.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r-- | arch/x86/kvm/vmx.c | 65 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 1 |
2 files changed, 65 insertions, 1 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 8432448fe35..c7600009dac 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -166,6 +166,9 @@ struct __packed vmcs12 { | |||
166 | u32 revision_id; | 166 | u32 revision_id; |
167 | u32 abort; | 167 | u32 abort; |
168 | 168 | ||
169 | u32 launch_state; /* set to 0 by VMCLEAR, to 1 by VMLAUNCH */ | ||
170 | u32 padding[7]; /* room for future expansion */ | ||
171 | |||
169 | u64 io_bitmap_a; | 172 | u64 io_bitmap_a; |
170 | u64 io_bitmap_b; | 173 | u64 io_bitmap_b; |
171 | u64 msr_bitmap; | 174 | u64 msr_bitmap; |
@@ -4814,6 +4817,66 @@ static void nested_vmx_failValid(struct kvm_vcpu *vcpu, | |||
4814 | get_vmcs12(vcpu)->vm_instruction_error = vm_instruction_error; | 4817 | get_vmcs12(vcpu)->vm_instruction_error = vm_instruction_error; |
4815 | } | 4818 | } |
4816 | 4819 | ||
4820 | /* Emulate the VMCLEAR instruction */ | ||
4821 | static int handle_vmclear(struct kvm_vcpu *vcpu) | ||
4822 | { | ||
4823 | struct vcpu_vmx *vmx = to_vmx(vcpu); | ||
4824 | gva_t gva; | ||
4825 | gpa_t vmptr; | ||
4826 | struct vmcs12 *vmcs12; | ||
4827 | struct page *page; | ||
4828 | struct x86_exception e; | ||
4829 | |||
4830 | if (!nested_vmx_check_permission(vcpu)) | ||
4831 | return 1; | ||
4832 | |||
4833 | if (get_vmx_mem_address(vcpu, vmcs_readl(EXIT_QUALIFICATION), | ||
4834 | vmcs_read32(VMX_INSTRUCTION_INFO), &gva)) | ||
4835 | return 1; | ||
4836 | |||
4837 | if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, &vmptr, | ||
4838 | sizeof(vmptr), &e)) { | ||
4839 | kvm_inject_page_fault(vcpu, &e); | ||
4840 | return 1; | ||
4841 | } | ||
4842 | |||
4843 | if (!IS_ALIGNED(vmptr, PAGE_SIZE)) { | ||
4844 | nested_vmx_failValid(vcpu, VMXERR_VMCLEAR_INVALID_ADDRESS); | ||
4845 | skip_emulated_instruction(vcpu); | ||
4846 | return 1; | ||
4847 | } | ||
4848 | |||
4849 | if (vmptr == vmx->nested.current_vmptr) { | ||
4850 | kunmap(vmx->nested.current_vmcs12_page); | ||
4851 | nested_release_page(vmx->nested.current_vmcs12_page); | ||
4852 | vmx->nested.current_vmptr = -1ull; | ||
4853 | vmx->nested.current_vmcs12 = NULL; | ||
4854 | } | ||
4855 | |||
4856 | page = nested_get_page(vcpu, vmptr); | ||
4857 | if (page == NULL) { | ||
4858 | /* | ||
4859 | * For accurate processor emulation, VMCLEAR beyond available | ||
4860 | * physical memory should do nothing at all. However, it is | ||
4861 | * possible that a nested vmx bug, not a guest hypervisor bug, | ||
4862 | * resulted in this case, so let's shut down before doing any | ||
4863 | * more damage: | ||
4864 | */ | ||
4865 | kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu); | ||
4866 | return 1; | ||
4867 | } | ||
4868 | vmcs12 = kmap(page); | ||
4869 | vmcs12->launch_state = 0; | ||
4870 | kunmap(page); | ||
4871 | nested_release_page(page); | ||
4872 | |||
4873 | nested_free_vmcs02(vmx, vmptr); | ||
4874 | |||
4875 | skip_emulated_instruction(vcpu); | ||
4876 | nested_vmx_succeed(vcpu); | ||
4877 | return 1; | ||
4878 | } | ||
4879 | |||
4817 | /* | 4880 | /* |
4818 | * The exit handlers return 1 if the exit was handled fully and guest execution | 4881 | * The exit handlers return 1 if the exit was handled fully and guest execution |
4819 | * may resume. Otherwise they set the kvm_run parameter to indicate what needs | 4882 | * may resume. Otherwise they set the kvm_run parameter to indicate what needs |
@@ -4835,7 +4898,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = { | |||
4835 | [EXIT_REASON_INVD] = handle_invd, | 4898 | [EXIT_REASON_INVD] = handle_invd, |
4836 | [EXIT_REASON_INVLPG] = handle_invlpg, | 4899 | [EXIT_REASON_INVLPG] = handle_invlpg, |
4837 | [EXIT_REASON_VMCALL] = handle_vmcall, | 4900 | [EXIT_REASON_VMCALL] = handle_vmcall, |
4838 | [EXIT_REASON_VMCLEAR] = handle_vmx_insn, | 4901 | [EXIT_REASON_VMCLEAR] = handle_vmclear, |
4839 | [EXIT_REASON_VMLAUNCH] = handle_vmx_insn, | 4902 | [EXIT_REASON_VMLAUNCH] = handle_vmx_insn, |
4840 | [EXIT_REASON_VMPTRLD] = handle_vmx_insn, | 4903 | [EXIT_REASON_VMPTRLD] = handle_vmx_insn, |
4841 | [EXIT_REASON_VMPTRST] = handle_vmx_insn, | 4904 | [EXIT_REASON_VMPTRST] = handle_vmx_insn, |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 27d12a3b189..c1b5a1817e4 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -347,6 +347,7 @@ void kvm_inject_page_fault(struct kvm_vcpu *vcpu, struct x86_exception *fault) | |||
347 | vcpu->arch.cr2 = fault->address; | 347 | vcpu->arch.cr2 = fault->address; |
348 | kvm_queue_exception_e(vcpu, PF_VECTOR, fault->error_code); | 348 | kvm_queue_exception_e(vcpu, PF_VECTOR, fault->error_code); |
349 | } | 349 | } |
350 | EXPORT_SYMBOL_GPL(kvm_inject_page_fault); | ||
350 | 351 | ||
351 | void kvm_propagate_fault(struct kvm_vcpu *vcpu, struct x86_exception *fault) | 352 | void kvm_propagate_fault(struct kvm_vcpu *vcpu, struct x86_exception *fault) |
352 | { | 353 | { |