aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEddie Dong <eddie.dong@intel.com>2007-05-21 00:28:09 -0400
committerAvi Kivity <avi@qumranet.com>2007-07-16 05:05:42 -0400
commit2cc51560aed0edb291341089d3475e1fbe8bfd04 (patch)
treee4fd63e0e79613fbb7e475dcdd0ea01c370e02a8
parentf2be4dd65437c60a4eb222bc40bc8caded62631a (diff)
KVM: VMX: Avoid saving and restoring msr_efer on lightweight vmexit
MSR_EFER.LME/LMA bits are automatically save/restored by VMX hardware, KVM only needs to save NX/SCE bits at time of heavy weight VM Exit. But clearing NX bits in host envirnment may cause system hang if the host page table is using EXB bits, thus we leave NX bits as it is. If Host NX=1 and guest NX=0, we can do guest page table EXB bits check before inserting a shadow pte (though no guest is expecting to see this kind of gp fault). If host NX=0, we present guest no Execute-Disable feature to guest, thus no host NX=0, guest NX=1 combination. This patch reduces raw vmexit time by ~27%. Me: fix compile warnings on i386. Signed-off-by: Yaozu (Eddie) Dong <eddie.dong@intel.com> Signed-off-by: Avi Kivity <avi@qumranet.com>
-rw-r--r--drivers/kvm/kvm.h2
-rw-r--r--drivers/kvm/kvm_main.c23
-rw-r--r--drivers/kvm/vmx.c67
3 files changed, 71 insertions, 21 deletions
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index c252efed49d9..db2bc6f168cd 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -255,6 +255,7 @@ struct kvm_stat {
255 u32 request_irq_exits; 255 u32 request_irq_exits;
256 u32 irq_exits; 256 u32 irq_exits;
257 u32 light_exits; 257 u32 light_exits;
258 u32 efer_reload;
258}; 259};
259 260
260struct kvm_vcpu { 261struct kvm_vcpu {
@@ -289,6 +290,7 @@ struct kvm_vcpu {
289 u64 ia32_misc_enable_msr; 290 u64 ia32_misc_enable_msr;
290 int nmsrs; 291 int nmsrs;
291 int save_nmsrs; 292 int save_nmsrs;
293 int msr_offset_efer;
292#ifdef CONFIG_X86_64 294#ifdef CONFIG_X86_64
293 int msr_offset_kernel_gs_base; 295 int msr_offset_kernel_gs_base;
294#endif 296#endif
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index 095d673b9efb..af07cd539bba 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -73,6 +73,7 @@ static struct kvm_stats_debugfs_item {
73 { "request_irq", STAT_OFFSET(request_irq_exits) }, 73 { "request_irq", STAT_OFFSET(request_irq_exits) },
74 { "irq_exits", STAT_OFFSET(irq_exits) }, 74 { "irq_exits", STAT_OFFSET(irq_exits) },
75 { "light_exits", STAT_OFFSET(light_exits) }, 75 { "light_exits", STAT_OFFSET(light_exits) },
76 { "efer_reload", STAT_OFFSET(efer_reload) },
76 { NULL } 77 { NULL }
77}; 78};
78 79
@@ -2378,6 +2379,27 @@ out:
2378 return r; 2379 return r;
2379} 2380}
2380 2381
2382static void cpuid_fix_nx_cap(struct kvm_vcpu *vcpu)
2383{
2384 u64 efer;
2385 int i;
2386 struct kvm_cpuid_entry *e, *entry;
2387
2388 rdmsrl(MSR_EFER, efer);
2389 entry = NULL;
2390 for (i = 0; i < vcpu->cpuid_nent; ++i) {
2391 e = &vcpu->cpuid_entries[i];
2392 if (e->function == 0x80000001) {
2393 entry = e;
2394 break;
2395 }
2396 }
2397 if (entry && (entry->edx & EFER_NX) && !(efer & EFER_NX)) {
2398 entry->edx &= ~(1 << 20);
2399 printk(KERN_INFO ": guest NX capability removed\n");
2400 }
2401}
2402
2381static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu, 2403static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
2382 struct kvm_cpuid *cpuid, 2404 struct kvm_cpuid *cpuid,
2383 struct kvm_cpuid_entry __user *entries) 2405 struct kvm_cpuid_entry __user *entries)
@@ -2392,6 +2414,7 @@ static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
2392 cpuid->nent * sizeof(struct kvm_cpuid_entry))) 2414 cpuid->nent * sizeof(struct kvm_cpuid_entry)))
2393 goto out; 2415 goto out;
2394 vcpu->cpuid_nent = cpuid->nent; 2416 vcpu->cpuid_nent = cpuid->nent;
2417 cpuid_fix_nx_cap(vcpu);
2395 return 0; 2418 return 0;
2396 2419
2397out: 2420out:
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index dc99191dbb4a..93e5bb2c40e3 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -42,6 +42,7 @@ static struct page *vmx_io_bitmap_b;
42#else 42#else
43#define HOST_IS_64 0 43#define HOST_IS_64 0
44#endif 44#endif
45#define EFER_SAVE_RESTORE_BITS ((u64)EFER_SCE)
45 46
46static struct vmcs_descriptor { 47static struct vmcs_descriptor {
47 int size; 48 int size;
@@ -85,6 +86,18 @@ static const u32 vmx_msr_index[] = {
85}; 86};
86#define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index) 87#define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index)
87 88
89static inline u64 msr_efer_save_restore_bits(struct vmx_msr_entry msr)
90{
91 return (u64)msr.data & EFER_SAVE_RESTORE_BITS;
92}
93
94static inline int msr_efer_need_save_restore(struct kvm_vcpu *vcpu)
95{
96 int efer_offset = vcpu->msr_offset_efer;
97 return msr_efer_save_restore_bits(vcpu->host_msrs[efer_offset]) !=
98 msr_efer_save_restore_bits(vcpu->guest_msrs[efer_offset]);
99}
100
88static inline int is_page_fault(u32 intr_info) 101static inline int is_page_fault(u32 intr_info)
89{ 102{
90 return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK | 103 return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
@@ -265,6 +278,19 @@ static void reload_tss(void)
265#endif 278#endif
266} 279}
267 280
281static void load_transition_efer(struct kvm_vcpu *vcpu)
282{
283 u64 trans_efer;
284 int efer_offset = vcpu->msr_offset_efer;
285
286 trans_efer = vcpu->host_msrs[efer_offset].data;
287 trans_efer &= ~EFER_SAVE_RESTORE_BITS;
288 trans_efer |= msr_efer_save_restore_bits(
289 vcpu->guest_msrs[efer_offset]);
290 wrmsrl(MSR_EFER, trans_efer);
291 vcpu->stat.efer_reload++;
292}
293
268static void vmx_save_host_state(struct kvm_vcpu *vcpu) 294static void vmx_save_host_state(struct kvm_vcpu *vcpu)
269{ 295{
270 struct vmx_host_state *hs = &vcpu->vmx_host_state; 296 struct vmx_host_state *hs = &vcpu->vmx_host_state;
@@ -308,6 +334,8 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu)
308 } 334 }
309#endif 335#endif
310 load_msrs(vcpu->guest_msrs, vcpu->save_nmsrs); 336 load_msrs(vcpu->guest_msrs, vcpu->save_nmsrs);
337 if (msr_efer_need_save_restore(vcpu))
338 load_transition_efer(vcpu);
311} 339}
312 340
313static void vmx_load_host_state(struct kvm_vcpu *vcpu) 341static void vmx_load_host_state(struct kvm_vcpu *vcpu)
@@ -336,6 +364,8 @@ static void vmx_load_host_state(struct kvm_vcpu *vcpu)
336 } 364 }
337 save_msrs(vcpu->guest_msrs, vcpu->save_nmsrs); 365 save_msrs(vcpu->guest_msrs, vcpu->save_nmsrs);
338 load_msrs(vcpu->host_msrs, vcpu->save_nmsrs); 366 load_msrs(vcpu->host_msrs, vcpu->save_nmsrs);
367 if (msr_efer_need_save_restore(vcpu))
368 load_msrs(vcpu->host_msrs + vcpu->msr_offset_efer, 1);
339} 369}
340 370
341/* 371/*
@@ -477,11 +507,13 @@ void move_msr_up(struct kvm_vcpu *vcpu, int from, int to)
477 */ 507 */
478static void setup_msrs(struct kvm_vcpu *vcpu) 508static void setup_msrs(struct kvm_vcpu *vcpu)
479{ 509{
480 int index, save_nmsrs; 510 int save_nmsrs;
481 511
482 save_nmsrs = 0; 512 save_nmsrs = 0;
483#ifdef CONFIG_X86_64 513#ifdef CONFIG_X86_64
484 if (is_long_mode(vcpu)) { 514 if (is_long_mode(vcpu)) {
515 int index;
516
485 index = __find_msr_index(vcpu, MSR_SYSCALL_MASK); 517 index = __find_msr_index(vcpu, MSR_SYSCALL_MASK);
486 if (index >= 0) 518 if (index >= 0)
487 move_msr_up(vcpu, index, save_nmsrs++); 519 move_msr_up(vcpu, index, save_nmsrs++);
@@ -509,22 +541,7 @@ static void setup_msrs(struct kvm_vcpu *vcpu)
509 vcpu->msr_offset_kernel_gs_base = 541 vcpu->msr_offset_kernel_gs_base =
510 __find_msr_index(vcpu, MSR_KERNEL_GS_BASE); 542 __find_msr_index(vcpu, MSR_KERNEL_GS_BASE);
511#endif 543#endif
512 index = __find_msr_index(vcpu, MSR_EFER); 544 vcpu->msr_offset_efer = __find_msr_index(vcpu, MSR_EFER);
513 if (index >= 0)
514 save_nmsrs = 1;
515 else {
516 save_nmsrs = 0;
517 index = 0;
518 }
519 vmcs_writel(VM_ENTRY_MSR_LOAD_ADDR,
520 virt_to_phys(vcpu->guest_msrs + index));
521 vmcs_writel(VM_EXIT_MSR_STORE_ADDR,
522 virt_to_phys(vcpu->guest_msrs + index));
523 vmcs_writel(VM_EXIT_MSR_LOAD_ADDR,
524 virt_to_phys(vcpu->host_msrs + index));
525 vmcs_write32(VM_EXIT_MSR_STORE_COUNT, save_nmsrs);
526 vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, save_nmsrs);
527 vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, save_nmsrs);
528} 545}
529 546
530/* 547/*
@@ -611,10 +628,15 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
611static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) 628static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
612{ 629{
613 struct vmx_msr_entry *msr; 630 struct vmx_msr_entry *msr;
631 int ret = 0;
632
614 switch (msr_index) { 633 switch (msr_index) {
615#ifdef CONFIG_X86_64 634#ifdef CONFIG_X86_64
616 case MSR_EFER: 635 case MSR_EFER:
617 return kvm_set_msr_common(vcpu, msr_index, data); 636 ret = kvm_set_msr_common(vcpu, msr_index, data);
637 if (vcpu->vmx_host_state.loaded)
638 load_transition_efer(vcpu);
639 break;
618 case MSR_FS_BASE: 640 case MSR_FS_BASE:
619 vmcs_writel(GUEST_FS_BASE, data); 641 vmcs_writel(GUEST_FS_BASE, data);
620 break; 642 break;
@@ -639,13 +661,13 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
639 if (msr) { 661 if (msr) {
640 msr->data = data; 662 msr->data = data;
641 if (vcpu->vmx_host_state.loaded) 663 if (vcpu->vmx_host_state.loaded)
642 load_msrs(vcpu->guest_msrs,vcpu->save_nmsrs); 664 load_msrs(vcpu->guest_msrs, vcpu->save_nmsrs);
643 break; 665 break;
644 } 666 }
645 return kvm_set_msr_common(vcpu, msr_index, data); 667 ret = kvm_set_msr_common(vcpu, msr_index, data);
646 } 668 }
647 669
648 return 0; 670 return ret;
649} 671}
650 672
651/* 673/*
@@ -1326,6 +1348,9 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
1326 1348
1327 asm ("mov $.Lkvm_vmx_return, %0" : "=r"(kvm_vmx_return)); 1349 asm ("mov $.Lkvm_vmx_return, %0" : "=r"(kvm_vmx_return));
1328 vmcs_writel(HOST_RIP, kvm_vmx_return); /* 22.2.5 */ 1350 vmcs_writel(HOST_RIP, kvm_vmx_return); /* 22.2.5 */
1351 vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0);
1352 vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0);
1353 vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0);
1329 1354
1330 rdmsr(MSR_IA32_SYSENTER_CS, host_sysenter_cs, junk); 1355 rdmsr(MSR_IA32_SYSENTER_CS, host_sysenter_cs, junk);
1331 vmcs_write32(HOST_IA32_SYSENTER_CS, host_sysenter_cs); 1356 vmcs_write32(HOST_IA32_SYSENTER_CS, host_sysenter_cs);