diff options
author | Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> | 2013-01-13 10:49:07 -0500 |
---|---|---|
committer | Marcelo Tosatti <mtosatti@redhat.com> | 2013-01-21 19:58:33 -0500 |
commit | 93c05d3ef25275829d421a255271595ac219a518 (patch) | |
tree | b987097751977ca63bd9a9ef53956cd0d14127c3 /arch/x86/kvm/x86.c | |
parent | 95b3cf69bdf8b27a02d878e24ca353cebb4e009e (diff) |
KVM: x86: improve reexecute_instruction
The current reexecute_instruction can not well detect the failed instruction
emulation. It allows guest to retry all the instructions except it accesses
on error pfn
For example, some cases are nested-write-protect - if the page we want to
write is used as PDE but it chains to itself. Under this case, we should
stop the emulation and report the case to userspace
Reviewed-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm/x86.c')
-rw-r--r-- | arch/x86/kvm/x86.c | 22 |
1 files changed, 18 insertions, 4 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 6f9cab071eca..e00dd0515a84 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -4751,7 +4751,8 @@ static int handle_emulation_failure(struct kvm_vcpu *vcpu) | |||
4751 | return r; | 4751 | return r; |
4752 | } | 4752 | } |
4753 | 4753 | ||
4754 | static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t cr2) | 4754 | static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t cr2, |
4755 | bool write_fault_to_shadow_pgtable) | ||
4755 | { | 4756 | { |
4756 | gpa_t gpa = cr2; | 4757 | gpa_t gpa = cr2; |
4757 | pfn_t pfn; | 4758 | pfn_t pfn; |
@@ -4808,7 +4809,13 @@ static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t cr2) | |||
4808 | * guest to let CPU execute the instruction. | 4809 | * guest to let CPU execute the instruction. |
4809 | */ | 4810 | */ |
4810 | kvm_mmu_unprotect_page(vcpu->kvm, gpa_to_gfn(gpa)); | 4811 | kvm_mmu_unprotect_page(vcpu->kvm, gpa_to_gfn(gpa)); |
4811 | return true; | 4812 | |
4813 | /* | ||
4814 | * If the access faults on its page table, it can not | ||
4815 | * be fixed by unprotecting shadow page and it should | ||
4816 | * be reported to userspace. | ||
4817 | */ | ||
4818 | return !write_fault_to_shadow_pgtable; | ||
4812 | } | 4819 | } |
4813 | 4820 | ||
4814 | static bool retry_instruction(struct x86_emulate_ctxt *ctxt, | 4821 | static bool retry_instruction(struct x86_emulate_ctxt *ctxt, |
@@ -4867,7 +4874,13 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, | |||
4867 | int r; | 4874 | int r; |
4868 | struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; | 4875 | struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; |
4869 | bool writeback = true; | 4876 | bool writeback = true; |
4877 | bool write_fault_to_spt = vcpu->arch.write_fault_to_shadow_pgtable; | ||
4870 | 4878 | ||
4879 | /* | ||
4880 | * Clear write_fault_to_shadow_pgtable here to ensure it is | ||
4881 | * never reused. | ||
4882 | */ | ||
4883 | vcpu->arch.write_fault_to_shadow_pgtable = false; | ||
4871 | kvm_clear_exception_queue(vcpu); | 4884 | kvm_clear_exception_queue(vcpu); |
4872 | 4885 | ||
4873 | if (!(emulation_type & EMULTYPE_NO_DECODE)) { | 4886 | if (!(emulation_type & EMULTYPE_NO_DECODE)) { |
@@ -4886,7 +4899,8 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, | |||
4886 | if (r != EMULATION_OK) { | 4899 | if (r != EMULATION_OK) { |
4887 | if (emulation_type & EMULTYPE_TRAP_UD) | 4900 | if (emulation_type & EMULTYPE_TRAP_UD) |
4888 | return EMULATE_FAIL; | 4901 | return EMULATE_FAIL; |
4889 | if (reexecute_instruction(vcpu, cr2)) | 4902 | if (reexecute_instruction(vcpu, cr2, |
4903 | write_fault_to_spt)) | ||
4890 | return EMULATE_DONE; | 4904 | return EMULATE_DONE; |
4891 | if (emulation_type & EMULTYPE_SKIP) | 4905 | if (emulation_type & EMULTYPE_SKIP) |
4892 | return EMULATE_FAIL; | 4906 | return EMULATE_FAIL; |
@@ -4916,7 +4930,7 @@ restart: | |||
4916 | return EMULATE_DONE; | 4930 | return EMULATE_DONE; |
4917 | 4931 | ||
4918 | if (r == EMULATION_FAILED) { | 4932 | if (r == EMULATION_FAILED) { |
4919 | if (reexecute_instruction(vcpu, cr2)) | 4933 | if (reexecute_instruction(vcpu, cr2, write_fault_to_spt)) |
4920 | return EMULATE_DONE; | 4934 | return EMULATE_DONE; |
4921 | 4935 | ||
4922 | return handle_emulation_failure(vcpu); | 4936 | return handle_emulation_failure(vcpu); |