diff options
author | Avi Kivity <avi@redhat.com> | 2010-04-28 09:40:38 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-05-19 04:36:31 -0400 |
commit | 61d2ef2ce3e0161bedf5d2867f546a8df77fa9bc (patch) | |
tree | d1e3423bac53d2222b4c607e15b29c6e7f9b546a /arch | |
parent | 5dfa3d170e17cbf9e4816a5ba2f5913c31c03e93 (diff) |
KVM: VMX: Add facility to atomically switch MSRs on guest entry/exit
Some guest msr values cannot be used on the host (for example. EFER.NX=0),
so we need to switch them atomically during guest entry or exit.
Add a facility to program the vmx msr autoload registers accordingly.
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kvm/vmx.c | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 2e8729678600..ae22dcf17211 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -98,6 +98,8 @@ module_param(ple_gap, int, S_IRUGO); | |||
98 | static int ple_window = KVM_VMX_DEFAULT_PLE_WINDOW; | 98 | static int ple_window = KVM_VMX_DEFAULT_PLE_WINDOW; |
99 | module_param(ple_window, int, S_IRUGO); | 99 | module_param(ple_window, int, S_IRUGO); |
100 | 100 | ||
101 | #define NR_AUTOLOAD_MSRS 1 | ||
102 | |||
101 | struct vmcs { | 103 | struct vmcs { |
102 | u32 revision_id; | 104 | u32 revision_id; |
103 | u32 abort; | 105 | u32 abort; |
@@ -125,6 +127,11 @@ struct vcpu_vmx { | |||
125 | u64 msr_guest_kernel_gs_base; | 127 | u64 msr_guest_kernel_gs_base; |
126 | #endif | 128 | #endif |
127 | struct vmcs *vmcs; | 129 | struct vmcs *vmcs; |
130 | struct msr_autoload { | ||
131 | unsigned nr; | ||
132 | struct vmx_msr_entry guest[NR_AUTOLOAD_MSRS]; | ||
133 | struct vmx_msr_entry host[NR_AUTOLOAD_MSRS]; | ||
134 | } msr_autoload; | ||
128 | struct { | 135 | struct { |
129 | int loaded; | 136 | int loaded; |
130 | u16 fs_sel, gs_sel, ldt_sel; | 137 | u16 fs_sel, gs_sel, ldt_sel; |
@@ -595,6 +602,46 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu) | |||
595 | vmcs_write32(EXCEPTION_BITMAP, eb); | 602 | vmcs_write32(EXCEPTION_BITMAP, eb); |
596 | } | 603 | } |
597 | 604 | ||
605 | static void clear_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr) | ||
606 | { | ||
607 | unsigned i; | ||
608 | struct msr_autoload *m = &vmx->msr_autoload; | ||
609 | |||
610 | for (i = 0; i < m->nr; ++i) | ||
611 | if (m->guest[i].index == msr) | ||
612 | break; | ||
613 | |||
614 | if (i == m->nr) | ||
615 | return; | ||
616 | --m->nr; | ||
617 | m->guest[i] = m->guest[m->nr]; | ||
618 | m->host[i] = m->host[m->nr]; | ||
619 | vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->nr); | ||
620 | vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->nr); | ||
621 | } | ||
622 | |||
623 | static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr, | ||
624 | u64 guest_val, u64 host_val) | ||
625 | { | ||
626 | unsigned i; | ||
627 | struct msr_autoload *m = &vmx->msr_autoload; | ||
628 | |||
629 | for (i = 0; i < m->nr; ++i) | ||
630 | if (m->guest[i].index == msr) | ||
631 | break; | ||
632 | |||
633 | if (i == m->nr) { | ||
634 | ++m->nr; | ||
635 | vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->nr); | ||
636 | vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->nr); | ||
637 | } | ||
638 | |||
639 | m->guest[i].index = msr; | ||
640 | m->guest[i].value = guest_val; | ||
641 | m->host[i].index = msr; | ||
642 | m->host[i].value = host_val; | ||
643 | } | ||
644 | |||
598 | static void reload_tss(void) | 645 | static void reload_tss(void) |
599 | { | 646 | { |
600 | /* | 647 | /* |
@@ -2470,7 +2517,9 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx) | |||
2470 | vmcs_writel(HOST_RIP, kvm_vmx_return); /* 22.2.5 */ | 2517 | vmcs_writel(HOST_RIP, kvm_vmx_return); /* 22.2.5 */ |
2471 | vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0); | 2518 | vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0); |
2472 | vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0); | 2519 | vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0); |
2520 | vmcs_write64(VM_EXIT_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.host)); | ||
2473 | vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0); | 2521 | vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0); |
2522 | vmcs_write64(VM_ENTRY_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.guest)); | ||
2474 | 2523 | ||
2475 | rdmsr(MSR_IA32_SYSENTER_CS, host_sysenter_cs, junk); | 2524 | rdmsr(MSR_IA32_SYSENTER_CS, host_sysenter_cs, junk); |
2476 | vmcs_write32(HOST_IA32_SYSENTER_CS, host_sysenter_cs); | 2525 | vmcs_write32(HOST_IA32_SYSENTER_CS, host_sysenter_cs); |