aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);