aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/vmx.c
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2010-04-28 09:40:38 -0400
committerAvi Kivity <avi@redhat.com>2010-05-19 04:36:31 -0400
commit61d2ef2ce3e0161bedf5d2867f546a8df77fa9bc (patch)
treed1e3423bac53d2222b4c607e15b29c6e7f9b546a /arch/x86/kvm/vmx.c
parent5dfa3d170e17cbf9e4816a5ba2f5913c31c03e93 (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/x86/kvm/vmx.c')
-rw-r--r--arch/x86/kvm/vmx.c49
1 files changed, 49 insertions, 0 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 2e872967860..ae22dcf1721 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -98,6 +98,8 @@ module_param(ple_gap, int, S_IRUGO);
98static int ple_window = KVM_VMX_DEFAULT_PLE_WINDOW; 98static int ple_window = KVM_VMX_DEFAULT_PLE_WINDOW;
99module_param(ple_window, int, S_IRUGO); 99module_param(ple_window, int, S_IRUGO);
100 100
101#define NR_AUTOLOAD_MSRS 1
102
101struct vmcs { 103struct 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
605static 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
623static 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
598static void reload_tss(void) 645static 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);