diff options
| author | Avi Kivity <avi@redhat.com> | 2010-12-05 11:56:11 -0500 |
|---|---|---|
| committer | Avi Kivity <avi@redhat.com> | 2011-01-12 04:31:16 -0500 |
| commit | aff48baa34c033318ad322ecbf2e4bcd891b29ca (patch) | |
| tree | 84955c55c812dd540cd0c54e5bdf6d3f5bfd08be | |
| parent | 9f8fe5043fd26627c2fa2e9a41896885e675000b (diff) | |
KVM: Fetch guest cr3 from hardware on demand
Instead of syncing the guest cr3 every exit, which is expensince on vmx
with ept enabled, sync it only on demand.
[sheng: fix incorrect cr3 seen by Windows XP]
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
| -rw-r--r-- | arch/x86/include/asm/kvm_host.h | 2 | ||||
| -rw-r--r-- | arch/x86/kvm/kvm_cache_regs.h | 2 | ||||
| -rw-r--r-- | arch/x86/kvm/svm.c | 5 | ||||
| -rw-r--r-- | arch/x86/kvm/vmx.c | 18 | ||||
| -rw-r--r-- | arch/x86/kvm/x86.c | 2 |
5 files changed, 23 insertions, 6 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 6268f6ce6434..95f026be8b5e 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
| @@ -117,6 +117,7 @@ enum kvm_reg { | |||
| 117 | 117 | ||
| 118 | enum kvm_reg_ex { | 118 | enum kvm_reg_ex { |
| 119 | VCPU_EXREG_PDPTR = NR_VCPU_REGS, | 119 | VCPU_EXREG_PDPTR = NR_VCPU_REGS, |
| 120 | VCPU_EXREG_CR3, | ||
| 120 | }; | 121 | }; |
| 121 | 122 | ||
| 122 | enum { | 123 | enum { |
| @@ -533,6 +534,7 @@ struct kvm_x86_ops { | |||
| 533 | struct kvm_segment *var, int seg); | 534 | struct kvm_segment *var, int seg); |
| 534 | void (*get_cs_db_l_bits)(struct kvm_vcpu *vcpu, int *db, int *l); | 535 | void (*get_cs_db_l_bits)(struct kvm_vcpu *vcpu, int *db, int *l); |
| 535 | void (*decache_cr0_guest_bits)(struct kvm_vcpu *vcpu); | 536 | void (*decache_cr0_guest_bits)(struct kvm_vcpu *vcpu); |
| 537 | void (*decache_cr3)(struct kvm_vcpu *vcpu); | ||
| 536 | void (*decache_cr4_guest_bits)(struct kvm_vcpu *vcpu); | 538 | void (*decache_cr4_guest_bits)(struct kvm_vcpu *vcpu); |
| 537 | void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0); | 539 | void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0); |
| 538 | void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3); | 540 | void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3); |
diff --git a/arch/x86/kvm/kvm_cache_regs.h b/arch/x86/kvm/kvm_cache_regs.h index a6bf8db326f5..3377d53fcd36 100644 --- a/arch/x86/kvm/kvm_cache_regs.h +++ b/arch/x86/kvm/kvm_cache_regs.h | |||
| @@ -75,6 +75,8 @@ static inline ulong kvm_read_cr4_bits(struct kvm_vcpu *vcpu, ulong mask) | |||
| 75 | 75 | ||
| 76 | static inline ulong kvm_read_cr3(struct kvm_vcpu *vcpu) | 76 | static inline ulong kvm_read_cr3(struct kvm_vcpu *vcpu) |
| 77 | { | 77 | { |
| 78 | if (!test_bit(VCPU_EXREG_CR3, (ulong *)&vcpu->arch.regs_avail)) | ||
| 79 | kvm_x86_ops->decache_cr3(vcpu); | ||
| 78 | return vcpu->arch.cr3; | 80 | return vcpu->arch.cr3; |
| 79 | } | 81 | } |
| 80 | 82 | ||
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index a7b04c0bd7a5..25bd1bc5aad2 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
| @@ -1327,6 +1327,10 @@ static void svm_decache_cr0_guest_bits(struct kvm_vcpu *vcpu) | |||
| 1327 | { | 1327 | { |
| 1328 | } | 1328 | } |
| 1329 | 1329 | ||
| 1330 | static void svm_decache_cr3(struct kvm_vcpu *vcpu) | ||
| 1331 | { | ||
| 1332 | } | ||
| 1333 | |||
| 1330 | static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu) | 1334 | static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu) |
| 1331 | { | 1335 | { |
| 1332 | } | 1336 | } |
| @@ -3871,6 +3875,7 @@ static struct kvm_x86_ops svm_x86_ops = { | |||
| 3871 | .get_cpl = svm_get_cpl, | 3875 | .get_cpl = svm_get_cpl, |
| 3872 | .get_cs_db_l_bits = kvm_get_cs_db_l_bits, | 3876 | .get_cs_db_l_bits = kvm_get_cs_db_l_bits, |
| 3873 | .decache_cr0_guest_bits = svm_decache_cr0_guest_bits, | 3877 | .decache_cr0_guest_bits = svm_decache_cr0_guest_bits, |
| 3878 | .decache_cr3 = svm_decache_cr3, | ||
| 3874 | .decache_cr4_guest_bits = svm_decache_cr4_guest_bits, | 3879 | .decache_cr4_guest_bits = svm_decache_cr4_guest_bits, |
| 3875 | .set_cr0 = svm_set_cr0, | 3880 | .set_cr0 = svm_set_cr0, |
| 3876 | .set_cr3 = svm_set_cr3, | 3881 | .set_cr3 = svm_set_cr3, |
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 141956ebf794..1896cada805f 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
| @@ -180,6 +180,7 @@ static int init_rmode(struct kvm *kvm); | |||
| 180 | static u64 construct_eptp(unsigned long root_hpa); | 180 | static u64 construct_eptp(unsigned long root_hpa); |
| 181 | static void kvm_cpu_vmxon(u64 addr); | 181 | static void kvm_cpu_vmxon(u64 addr); |
| 182 | static void kvm_cpu_vmxoff(void); | 182 | static void kvm_cpu_vmxoff(void); |
| 183 | static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3); | ||
| 183 | 184 | ||
| 184 | static DEFINE_PER_CPU(struct vmcs *, vmxarea); | 185 | static DEFINE_PER_CPU(struct vmcs *, vmxarea); |
| 185 | static DEFINE_PER_CPU(struct vmcs *, current_vmcs); | 186 | static DEFINE_PER_CPU(struct vmcs *, current_vmcs); |
| @@ -1866,6 +1867,13 @@ static void vmx_decache_cr0_guest_bits(struct kvm_vcpu *vcpu) | |||
| 1866 | vcpu->arch.cr0 |= vmcs_readl(GUEST_CR0) & cr0_guest_owned_bits; | 1867 | vcpu->arch.cr0 |= vmcs_readl(GUEST_CR0) & cr0_guest_owned_bits; |
| 1867 | } | 1868 | } |
| 1868 | 1869 | ||
| 1870 | static void vmx_decache_cr3(struct kvm_vcpu *vcpu) | ||
| 1871 | { | ||
| 1872 | if (enable_ept && is_paging(vcpu)) | ||
| 1873 | vcpu->arch.cr3 = vmcs_readl(GUEST_CR3); | ||
| 1874 | __set_bit(VCPU_EXREG_CR3, (ulong *)&vcpu->arch.regs_avail); | ||
| 1875 | } | ||
| 1876 | |||
| 1869 | static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu) | 1877 | static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu) |
| 1870 | { | 1878 | { |
| 1871 | ulong cr4_guest_owned_bits = vcpu->arch.cr4_guest_owned_bits; | 1879 | ulong cr4_guest_owned_bits = vcpu->arch.cr4_guest_owned_bits; |
| @@ -1909,6 +1917,7 @@ static void ept_update_paging_mode_cr0(unsigned long *hw_cr0, | |||
| 1909 | unsigned long cr0, | 1917 | unsigned long cr0, |
| 1910 | struct kvm_vcpu *vcpu) | 1918 | struct kvm_vcpu *vcpu) |
| 1911 | { | 1919 | { |
| 1920 | vmx_decache_cr3(vcpu); | ||
| 1912 | if (!(cr0 & X86_CR0_PG)) { | 1921 | if (!(cr0 & X86_CR0_PG)) { |
| 1913 | /* From paging/starting to nonpaging */ | 1922 | /* From paging/starting to nonpaging */ |
| 1914 | vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, | 1923 | vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, |
| @@ -3756,11 +3765,6 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu) | |||
| 3756 | if (vmx->emulation_required && emulate_invalid_guest_state) | 3765 | if (vmx->emulation_required && emulate_invalid_guest_state) |
| 3757 | return handle_invalid_guest_state(vcpu); | 3766 | return handle_invalid_guest_state(vcpu); |
| 3758 | 3767 | ||
| 3759 | /* Access CR3 don't cause VMExit in paging mode, so we need | ||
| 3760 | * to sync with guest real CR3. */ | ||
| 3761 | if (enable_ept && is_paging(vcpu)) | ||
| 3762 | vcpu->arch.cr3 = vmcs_readl(GUEST_CR3); | ||
| 3763 | |||
| 3764 | if (exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY) { | 3768 | if (exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY) { |
| 3765 | vcpu->run->exit_reason = KVM_EXIT_FAIL_ENTRY; | 3769 | vcpu->run->exit_reason = KVM_EXIT_FAIL_ENTRY; |
| 3766 | vcpu->run->fail_entry.hardware_entry_failure_reason | 3770 | vcpu->run->fail_entry.hardware_entry_failure_reason |
| @@ -4077,7 +4081,8 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu) | |||
| 4077 | ); | 4081 | ); |
| 4078 | 4082 | ||
| 4079 | vcpu->arch.regs_avail = ~((1 << VCPU_REGS_RIP) | (1 << VCPU_REGS_RSP) | 4083 | vcpu->arch.regs_avail = ~((1 << VCPU_REGS_RIP) | (1 << VCPU_REGS_RSP) |
| 4080 | | (1 << VCPU_EXREG_PDPTR)); | 4084 | | (1 << VCPU_EXREG_PDPTR) |
| 4085 | | (1 << VCPU_EXREG_CR3)); | ||
| 4081 | vcpu->arch.regs_dirty = 0; | 4086 | vcpu->arch.regs_dirty = 0; |
| 4082 | 4087 | ||
| 4083 | vmx->idt_vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD); | 4088 | vmx->idt_vectoring_info = vmcs_read32(IDT_VECTORING_INFO_FIELD); |
| @@ -4344,6 +4349,7 @@ static struct kvm_x86_ops vmx_x86_ops = { | |||
| 4344 | .get_cpl = vmx_get_cpl, | 4349 | .get_cpl = vmx_get_cpl, |
| 4345 | .get_cs_db_l_bits = vmx_get_cs_db_l_bits, | 4350 | .get_cs_db_l_bits = vmx_get_cs_db_l_bits, |
| 4346 | .decache_cr0_guest_bits = vmx_decache_cr0_guest_bits, | 4351 | .decache_cr0_guest_bits = vmx_decache_cr0_guest_bits, |
| 4352 | .decache_cr3 = vmx_decache_cr3, | ||
| 4347 | .decache_cr4_guest_bits = vmx_decache_cr4_guest_bits, | 4353 | .decache_cr4_guest_bits = vmx_decache_cr4_guest_bits, |
| 4348 | .set_cr0 = vmx_set_cr0, | 4354 | .set_cr0 = vmx_set_cr0, |
| 4349 | .set_cr3 = vmx_set_cr3, | 4355 | .set_cr3 = vmx_set_cr3, |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 6e50314d64fb..fa708c9a7437 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
| @@ -667,6 +667,7 @@ int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) | |||
| 667 | if (unlikely(!gfn_to_memslot(vcpu->kvm, cr3 >> PAGE_SHIFT))) | 667 | if (unlikely(!gfn_to_memslot(vcpu->kvm, cr3 >> PAGE_SHIFT))) |
| 668 | return 1; | 668 | return 1; |
| 669 | vcpu->arch.cr3 = cr3; | 669 | vcpu->arch.cr3 = cr3; |
| 670 | __set_bit(VCPU_EXREG_CR3, (ulong *)&vcpu->arch.regs_avail); | ||
| 670 | vcpu->arch.mmu.new_cr3(vcpu); | 671 | vcpu->arch.mmu.new_cr3(vcpu); |
| 671 | return 0; | 672 | return 0; |
| 672 | } | 673 | } |
| @@ -5583,6 +5584,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, | |||
| 5583 | vcpu->arch.cr2 = sregs->cr2; | 5584 | vcpu->arch.cr2 = sregs->cr2; |
| 5584 | mmu_reset_needed |= kvm_read_cr3(vcpu) != sregs->cr3; | 5585 | mmu_reset_needed |= kvm_read_cr3(vcpu) != sregs->cr3; |
| 5585 | vcpu->arch.cr3 = sregs->cr3; | 5586 | vcpu->arch.cr3 = sregs->cr3; |
| 5587 | __set_bit(VCPU_EXREG_CR3, (ulong *)&vcpu->arch.regs_avail); | ||
| 5586 | 5588 | ||
| 5587 | kvm_set_cr8(vcpu, sregs->cr8); | 5589 | kvm_set_cr8(vcpu, sregs->cr8); |
| 5588 | 5590 | ||
