diff options
| author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-17 14:50:26 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-17 14:50:26 -0400 |
| commit | 49c13b51a15f1ba9f6d47e26e4a3886c4f3931e2 (patch) | |
| tree | a96d7fc5884e56a61993f9393afa9077f8068b47 /drivers/kvm/svm.c | |
| parent | 492559af235eb56884d62553f191c0b5c4def990 (diff) | |
| parent | cec9ad279b66793bee0b5009b7ca311060061efd (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/avi/kvm
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/avi/kvm: (80 commits)
KVM: Use CPU_DYING for disabling virtualization
KVM: Tune hotplug/suspend IPIs
KVM: Keep track of which cpus have virtualization enabled
SMP: Allow smp_call_function_single() to current cpu
i386: Allow smp_call_function_single() to current cpu
x86_64: Allow smp_call_function_single() to current cpu
HOTPLUG: Adapt thermal throttle to CPU_DYING
HOTPLUG: Adapt cpuset hotplug callback to CPU_DYING
HOTPLUG: Add CPU_DYING notifier
KVM: Clean up #includes
KVM: Remove kvmfs in favor of the anonymous inodes source
KVM: SVM: Reliably detect if SVM was disabled by BIOS
KVM: VMX: Remove unnecessary code in vmx_tlb_flush()
KVM: MMU: Fix Wrong tlb flush order
KVM: VMX: Reinitialize the real-mode tss when entering real mode
KVM: Avoid useless memory write when possible
KVM: Fix x86 emulator writeback
KVM: Add support for in-kernel pio handlers
KVM: VMX: Fix interrupt checking on lightweight exit
KVM: Adds support for in-kernel mmio handlers
...
Diffstat (limited to 'drivers/kvm/svm.c')
| -rw-r--r-- | drivers/kvm/svm.c | 59 |
1 files changed, 37 insertions, 22 deletions
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c index fa17d6d4f0cb..bc818cc126e3 100644 --- a/drivers/kvm/svm.c +++ b/drivers/kvm/svm.c | |||
| @@ -14,16 +14,17 @@ | |||
| 14 | * | 14 | * |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | #include "kvm_svm.h" | ||
| 18 | #include "x86_emulate.h" | ||
| 19 | |||
| 17 | #include <linux/module.h> | 20 | #include <linux/module.h> |
| 18 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
| 19 | #include <linux/vmalloc.h> | 22 | #include <linux/vmalloc.h> |
| 20 | #include <linux/highmem.h> | 23 | #include <linux/highmem.h> |
| 21 | #include <linux/profile.h> | 24 | #include <linux/profile.h> |
| 22 | #include <linux/sched.h> | 25 | #include <linux/sched.h> |
| 23 | #include <asm/desc.h> | ||
| 24 | 26 | ||
| 25 | #include "kvm_svm.h" | 27 | #include <asm/desc.h> |
| 26 | #include "x86_emulate.h" | ||
| 27 | 28 | ||
| 28 | MODULE_AUTHOR("Qumranet"); | 29 | MODULE_AUTHOR("Qumranet"); |
| 29 | MODULE_LICENSE("GPL"); | 30 | MODULE_LICENSE("GPL"); |
| @@ -378,7 +379,7 @@ static __init int svm_hardware_setup(void) | |||
| 378 | int cpu; | 379 | int cpu; |
| 379 | struct page *iopm_pages; | 380 | struct page *iopm_pages; |
| 380 | struct page *msrpm_pages; | 381 | struct page *msrpm_pages; |
| 381 | void *msrpm_va; | 382 | void *iopm_va, *msrpm_va; |
| 382 | int r; | 383 | int r; |
| 383 | 384 | ||
| 384 | kvm_emulator_want_group7_invlpg(); | 385 | kvm_emulator_want_group7_invlpg(); |
| @@ -387,8 +388,10 @@ static __init int svm_hardware_setup(void) | |||
| 387 | 388 | ||
| 388 | if (!iopm_pages) | 389 | if (!iopm_pages) |
| 389 | return -ENOMEM; | 390 | return -ENOMEM; |
| 390 | memset(page_address(iopm_pages), 0xff, | 391 | |
| 391 | PAGE_SIZE * (1 << IOPM_ALLOC_ORDER)); | 392 | iopm_va = page_address(iopm_pages); |
| 393 | memset(iopm_va, 0xff, PAGE_SIZE * (1 << IOPM_ALLOC_ORDER)); | ||
| 394 | clear_bit(0x80, iopm_va); /* allow direct access to PC debug port */ | ||
| 392 | iopm_base = page_to_pfn(iopm_pages) << PAGE_SHIFT; | 395 | iopm_base = page_to_pfn(iopm_pages) << PAGE_SHIFT; |
| 393 | 396 | ||
| 394 | 397 | ||
| @@ -579,7 +582,7 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu) | |||
| 579 | goto out2; | 582 | goto out2; |
| 580 | 583 | ||
| 581 | vcpu->svm->vmcb = page_address(page); | 584 | vcpu->svm->vmcb = page_address(page); |
| 582 | memset(vcpu->svm->vmcb, 0, PAGE_SIZE); | 585 | clear_page(vcpu->svm->vmcb); |
| 583 | vcpu->svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT; | 586 | vcpu->svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT; |
| 584 | vcpu->svm->asid_generation = 0; | 587 | vcpu->svm->asid_generation = 0; |
| 585 | memset(vcpu->svm->db_regs, 0, sizeof(vcpu->svm->db_regs)); | 588 | memset(vcpu->svm->db_regs, 0, sizeof(vcpu->svm->db_regs)); |
| @@ -587,9 +590,9 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu) | |||
| 587 | 590 | ||
| 588 | fx_init(vcpu); | 591 | fx_init(vcpu); |
| 589 | vcpu->fpu_active = 1; | 592 | vcpu->fpu_active = 1; |
| 590 | vcpu->apic_base = 0xfee00000 | | 593 | vcpu->apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE; |
| 591 | /*for vcpu 0*/ MSR_IA32_APICBASE_BSP | | 594 | if (vcpu == &vcpu->kvm->vcpus[0]) |
| 592 | MSR_IA32_APICBASE_ENABLE; | 595 | vcpu->apic_base |= MSR_IA32_APICBASE_BSP; |
| 593 | 596 | ||
| 594 | return 0; | 597 | return 0; |
| 595 | 598 | ||
| @@ -955,7 +958,7 @@ static int shutdown_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
| 955 | * VMCB is undefined after a SHUTDOWN intercept | 958 | * VMCB is undefined after a SHUTDOWN intercept |
| 956 | * so reinitialize it. | 959 | * so reinitialize it. |
| 957 | */ | 960 | */ |
| 958 | memset(vcpu->svm->vmcb, 0, PAGE_SIZE); | 961 | clear_page(vcpu->svm->vmcb); |
| 959 | init_vmcb(vcpu->svm->vmcb); | 962 | init_vmcb(vcpu->svm->vmcb); |
| 960 | 963 | ||
| 961 | kvm_run->exit_reason = KVM_EXIT_SHUTDOWN; | 964 | kvm_run->exit_reason = KVM_EXIT_SHUTDOWN; |
| @@ -1113,12 +1116,7 @@ static int halt_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
| 1113 | { | 1116 | { |
| 1114 | vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 1; | 1117 | vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 1; |
| 1115 | skip_emulated_instruction(vcpu); | 1118 | skip_emulated_instruction(vcpu); |
| 1116 | if (vcpu->irq_summary) | 1119 | return kvm_emulate_halt(vcpu); |
| 1117 | return 1; | ||
| 1118 | |||
| 1119 | kvm_run->exit_reason = KVM_EXIT_HLT; | ||
| 1120 | ++vcpu->stat.halt_exits; | ||
| 1121 | return 0; | ||
| 1122 | } | 1120 | } |
| 1123 | 1121 | ||
| 1124 | static int vmmcall_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | 1122 | static int vmmcall_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) |
| @@ -1473,6 +1471,11 @@ static void load_db_regs(unsigned long *db_regs) | |||
| 1473 | asm volatile ("mov %0, %%dr3" : : "r"(db_regs[3])); | 1471 | asm volatile ("mov %0, %%dr3" : : "r"(db_regs[3])); |
| 1474 | } | 1472 | } |
| 1475 | 1473 | ||
| 1474 | static void svm_flush_tlb(struct kvm_vcpu *vcpu) | ||
| 1475 | { | ||
| 1476 | force_new_asid(vcpu); | ||
| 1477 | } | ||
| 1478 | |||
| 1476 | static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | 1479 | static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) |
| 1477 | { | 1480 | { |
| 1478 | u16 fs_selector; | 1481 | u16 fs_selector; |
| @@ -1481,11 +1484,20 @@ static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
| 1481 | int r; | 1484 | int r; |
| 1482 | 1485 | ||
| 1483 | again: | 1486 | again: |
| 1487 | r = kvm_mmu_reload(vcpu); | ||
| 1488 | if (unlikely(r)) | ||
| 1489 | return r; | ||
| 1490 | |||
| 1484 | if (!vcpu->mmio_read_completed) | 1491 | if (!vcpu->mmio_read_completed) |
| 1485 | do_interrupt_requests(vcpu, kvm_run); | 1492 | do_interrupt_requests(vcpu, kvm_run); |
| 1486 | 1493 | ||
| 1487 | clgi(); | 1494 | clgi(); |
| 1488 | 1495 | ||
| 1496 | vcpu->guest_mode = 1; | ||
| 1497 | if (vcpu->requests) | ||
| 1498 | if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests)) | ||
| 1499 | svm_flush_tlb(vcpu); | ||
| 1500 | |||
| 1489 | pre_svm_run(vcpu); | 1501 | pre_svm_run(vcpu); |
| 1490 | 1502 | ||
| 1491 | save_host_msrs(vcpu); | 1503 | save_host_msrs(vcpu); |
| @@ -1617,6 +1629,8 @@ again: | |||
| 1617 | #endif | 1629 | #endif |
| 1618 | : "cc", "memory" ); | 1630 | : "cc", "memory" ); |
| 1619 | 1631 | ||
| 1632 | vcpu->guest_mode = 0; | ||
| 1633 | |||
| 1620 | if (vcpu->fpu_active) { | 1634 | if (vcpu->fpu_active) { |
| 1621 | fx_save(vcpu->guest_fx_image); | 1635 | fx_save(vcpu->guest_fx_image); |
| 1622 | fx_restore(vcpu->host_fx_image); | 1636 | fx_restore(vcpu->host_fx_image); |
| @@ -1681,11 +1695,6 @@ again: | |||
| 1681 | return r; | 1695 | return r; |
| 1682 | } | 1696 | } |
| 1683 | 1697 | ||
| 1684 | static void svm_flush_tlb(struct kvm_vcpu *vcpu) | ||
| 1685 | { | ||
| 1686 | force_new_asid(vcpu); | ||
| 1687 | } | ||
| 1688 | |||
| 1689 | static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root) | 1698 | static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root) |
| 1690 | { | 1699 | { |
| 1691 | vcpu->svm->vmcb->save.cr3 = root; | 1700 | vcpu->svm->vmcb->save.cr3 = root; |
| @@ -1727,6 +1736,12 @@ static void svm_inject_page_fault(struct kvm_vcpu *vcpu, | |||
| 1727 | 1736 | ||
| 1728 | static int is_disabled(void) | 1737 | static int is_disabled(void) |
| 1729 | { | 1738 | { |
| 1739 | u64 vm_cr; | ||
| 1740 | |||
| 1741 | rdmsrl(MSR_VM_CR, vm_cr); | ||
| 1742 | if (vm_cr & (1 << SVM_VM_CR_SVM_DISABLE)) | ||
| 1743 | return 1; | ||
| 1744 | |||
| 1730 | return 0; | 1745 | return 0; |
| 1731 | } | 1746 | } |
| 1732 | 1747 | ||
