diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-10-05 15:07:39 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-10-05 15:07:39 -0400 |
| commit | 19d031e052bc213cdcbee70696d476136994b8c1 (patch) | |
| tree | 906e78a07d15e0154692f82489387e3ad7f3f94b | |
| parent | e8d809c61325a2f799dc753b0ac72ace6958b92c (diff) | |
| parent | 3da0dd433dc399a8c0124d0614d82a09b6a49bce (diff) | |
Merge branch 'kvm-updates/2.6.32' of git://git.kernel.org/pub/scm/virt/kvm/kvm
* 'kvm-updates/2.6.32' of git://git.kernel.org/pub/scm/virt/kvm/kvm:
KVM: add support for change_pte mmu notifiers
KVM: MMU: add SPTE_HOST_WRITEABLE flag to the shadow ptes
KVM: MMU: dont hold pagecount reference for mapped sptes pages
KVM: Prevent overflow in KVM_GET_SUPPORTED_CPUID
KVM: VMX: flush TLB with INVEPT on cpu migration
KVM: fix LAPIC timer period overflow
KVM: s390: fix memsize >= 4G
KVM: SVM: Handle tsc in svm_get_msr/svm_set_msr correctly
KVM: SVM: Fix tsc offset adjustment when running nested
| -rw-r--r-- | arch/s390/kvm/kvm-s390.h | 2 | ||||
| -rw-r--r-- | arch/x86/include/asm/kvm_host.h | 1 | ||||
| -rw-r--r-- | arch/x86/kvm/lapic.c | 2 | ||||
| -rw-r--r-- | arch/x86/kvm/mmu.c | 84 | ||||
| -rw-r--r-- | arch/x86/kvm/paging_tmpl.h | 18 | ||||
| -rw-r--r-- | arch/x86/kvm/svm.c | 25 | ||||
| -rw-r--r-- | arch/x86/kvm/vmx.c | 2 | ||||
| -rw-r--r-- | arch/x86/kvm/x86.c | 2 | ||||
| -rw-r--r-- | virt/kvm/kvm_main.c | 14 |
9 files changed, 120 insertions, 30 deletions
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index ec5eee7c25d8..06cce8285ba0 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h | |||
| @@ -58,7 +58,7 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, | |||
| 58 | int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code); | 58 | int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code); |
| 59 | int kvm_s390_inject_sigp_stop(struct kvm_vcpu *vcpu, int action); | 59 | int kvm_s390_inject_sigp_stop(struct kvm_vcpu *vcpu, int action); |
| 60 | 60 | ||
| 61 | static inline int kvm_s390_vcpu_get_memsize(struct kvm_vcpu *vcpu) | 61 | static inline long kvm_s390_vcpu_get_memsize(struct kvm_vcpu *vcpu) |
| 62 | { | 62 | { |
| 63 | return vcpu->arch.sie_block->gmslm | 63 | return vcpu->arch.sie_block->gmslm |
| 64 | - vcpu->arch.sie_block->gmsor | 64 | - vcpu->arch.sie_block->gmsor |
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 3be000435fad..d83892226f73 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
| @@ -796,6 +796,7 @@ asmlinkage void kvm_handle_fault_on_reboot(void); | |||
| 796 | #define KVM_ARCH_WANT_MMU_NOTIFIER | 796 | #define KVM_ARCH_WANT_MMU_NOTIFIER |
| 797 | int kvm_unmap_hva(struct kvm *kvm, unsigned long hva); | 797 | int kvm_unmap_hva(struct kvm *kvm, unsigned long hva); |
| 798 | int kvm_age_hva(struct kvm *kvm, unsigned long hva); | 798 | int kvm_age_hva(struct kvm *kvm, unsigned long hva); |
| 799 | void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte); | ||
| 799 | int cpuid_maxphyaddr(struct kvm_vcpu *vcpu); | 800 | int cpuid_maxphyaddr(struct kvm_vcpu *vcpu); |
| 800 | int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu); | 801 | int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu); |
| 801 | int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu); | 802 | int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu); |
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 1ae5ceba7eb2..7024224f0fc8 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
| @@ -664,7 +664,7 @@ static void start_apic_timer(struct kvm_lapic *apic) | |||
| 664 | { | 664 | { |
| 665 | ktime_t now = apic->lapic_timer.timer.base->get_time(); | 665 | ktime_t now = apic->lapic_timer.timer.base->get_time(); |
| 666 | 666 | ||
| 667 | apic->lapic_timer.period = apic_get_reg(apic, APIC_TMICT) * | 667 | apic->lapic_timer.period = (u64)apic_get_reg(apic, APIC_TMICT) * |
| 668 | APIC_BUS_CYCLE_NS * apic->divide_count; | 668 | APIC_BUS_CYCLE_NS * apic->divide_count; |
| 669 | atomic_set(&apic->lapic_timer.pending, 0); | 669 | atomic_set(&apic->lapic_timer.pending, 0); |
| 670 | 670 | ||
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index eca41ae9f453..685a4ffac8e6 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
| @@ -156,6 +156,8 @@ module_param(oos_shadow, bool, 0644); | |||
| 156 | #define CREATE_TRACE_POINTS | 156 | #define CREATE_TRACE_POINTS |
| 157 | #include "mmutrace.h" | 157 | #include "mmutrace.h" |
| 158 | 158 | ||
| 159 | #define SPTE_HOST_WRITEABLE (1ULL << PT_FIRST_AVAIL_BITS_SHIFT) | ||
| 160 | |||
| 159 | #define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level) | 161 | #define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level) |
| 160 | 162 | ||
| 161 | struct kvm_rmap_desc { | 163 | struct kvm_rmap_desc { |
| @@ -634,9 +636,7 @@ static void rmap_remove(struct kvm *kvm, u64 *spte) | |||
| 634 | if (*spte & shadow_accessed_mask) | 636 | if (*spte & shadow_accessed_mask) |
| 635 | kvm_set_pfn_accessed(pfn); | 637 | kvm_set_pfn_accessed(pfn); |
| 636 | if (is_writeble_pte(*spte)) | 638 | if (is_writeble_pte(*spte)) |
| 637 | kvm_release_pfn_dirty(pfn); | 639 | kvm_set_pfn_dirty(pfn); |
| 638 | else | ||
| 639 | kvm_release_pfn_clean(pfn); | ||
| 640 | rmapp = gfn_to_rmap(kvm, sp->gfns[spte - sp->spt], sp->role.level); | 640 | rmapp = gfn_to_rmap(kvm, sp->gfns[spte - sp->spt], sp->role.level); |
| 641 | if (!*rmapp) { | 641 | if (!*rmapp) { |
| 642 | printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte); | 642 | printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte); |
| @@ -748,7 +748,7 @@ static int rmap_write_protect(struct kvm *kvm, u64 gfn) | |||
| 748 | return write_protected; | 748 | return write_protected; |
| 749 | } | 749 | } |
| 750 | 750 | ||
| 751 | static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp) | 751 | static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp, u64 data) |
| 752 | { | 752 | { |
| 753 | u64 *spte; | 753 | u64 *spte; |
| 754 | int need_tlb_flush = 0; | 754 | int need_tlb_flush = 0; |
| @@ -763,8 +763,45 @@ static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp) | |||
| 763 | return need_tlb_flush; | 763 | return need_tlb_flush; |
| 764 | } | 764 | } |
| 765 | 765 | ||
| 766 | static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, | 766 | static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp, u64 data) |
| 767 | int (*handler)(struct kvm *kvm, unsigned long *rmapp)) | 767 | { |
| 768 | int need_flush = 0; | ||
| 769 | u64 *spte, new_spte; | ||
| 770 | pte_t *ptep = (pte_t *)data; | ||
| 771 | pfn_t new_pfn; | ||
| 772 | |||
| 773 | WARN_ON(pte_huge(*ptep)); | ||
| 774 | new_pfn = pte_pfn(*ptep); | ||
| 775 | spte = rmap_next(kvm, rmapp, NULL); | ||
| 776 | while (spte) { | ||
| 777 | BUG_ON(!is_shadow_present_pte(*spte)); | ||
| 778 | rmap_printk("kvm_set_pte_rmapp: spte %p %llx\n", spte, *spte); | ||
| 779 | need_flush = 1; | ||
| 780 | if (pte_write(*ptep)) { | ||
| 781 | rmap_remove(kvm, spte); | ||
| 782 | __set_spte(spte, shadow_trap_nonpresent_pte); | ||
| 783 | spte = rmap_next(kvm, rmapp, NULL); | ||
| 784 | } else { | ||
| 785 | new_spte = *spte &~ (PT64_BASE_ADDR_MASK); | ||
| 786 | new_spte |= (u64)new_pfn << PAGE_SHIFT; | ||
| 787 | |||
| 788 | new_spte &= ~PT_WRITABLE_MASK; | ||
| 789 | new_spte &= ~SPTE_HOST_WRITEABLE; | ||
| 790 | if (is_writeble_pte(*spte)) | ||
| 791 | kvm_set_pfn_dirty(spte_to_pfn(*spte)); | ||
| 792 | __set_spte(spte, new_spte); | ||
| 793 | spte = rmap_next(kvm, rmapp, spte); | ||
| 794 | } | ||
| 795 | } | ||
| 796 | if (need_flush) | ||
| 797 | kvm_flush_remote_tlbs(kvm); | ||
| 798 | |||
| 799 | return 0; | ||
| 800 | } | ||
| 801 | |||
| 802 | static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, u64 data, | ||
| 803 | int (*handler)(struct kvm *kvm, unsigned long *rmapp, | ||
| 804 | u64 data)) | ||
| 768 | { | 805 | { |
| 769 | int i, j; | 806 | int i, j; |
| 770 | int retval = 0; | 807 | int retval = 0; |
| @@ -786,13 +823,15 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, | |||
| 786 | if (hva >= start && hva < end) { | 823 | if (hva >= start && hva < end) { |
| 787 | gfn_t gfn_offset = (hva - start) >> PAGE_SHIFT; | 824 | gfn_t gfn_offset = (hva - start) >> PAGE_SHIFT; |
| 788 | 825 | ||
| 789 | retval |= handler(kvm, &memslot->rmap[gfn_offset]); | 826 | retval |= handler(kvm, &memslot->rmap[gfn_offset], |
| 827 | data); | ||
| 790 | 828 | ||
| 791 | for (j = 0; j < KVM_NR_PAGE_SIZES - 1; ++j) { | 829 | for (j = 0; j < KVM_NR_PAGE_SIZES - 1; ++j) { |
| 792 | int idx = gfn_offset; | 830 | int idx = gfn_offset; |
| 793 | idx /= KVM_PAGES_PER_HPAGE(PT_DIRECTORY_LEVEL + j); | 831 | idx /= KVM_PAGES_PER_HPAGE(PT_DIRECTORY_LEVEL + j); |
| 794 | retval |= handler(kvm, | 832 | retval |= handler(kvm, |
| 795 | &memslot->lpage_info[j][idx].rmap_pde); | 833 | &memslot->lpage_info[j][idx].rmap_pde, |
| 834 | data); | ||
| 796 | } | 835 | } |
| 797 | } | 836 | } |
| 798 | } | 837 | } |
| @@ -802,10 +841,15 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, | |||
| 802 | 841 | ||
| 803 | int kvm_unmap_hva(struct kvm *kvm, unsigned long hva) | 842 | int kvm_unmap_hva(struct kvm *kvm, unsigned long hva) |
| 804 | { | 843 | { |
| 805 | return kvm_handle_hva(kvm, hva, kvm_unmap_rmapp); | 844 | return kvm_handle_hva(kvm, hva, 0, kvm_unmap_rmapp); |
| 806 | } | 845 | } |
| 807 | 846 | ||
| 808 | static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp) | 847 | void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte) |
| 848 | { | ||
| 849 | kvm_handle_hva(kvm, hva, (u64)&pte, kvm_set_pte_rmapp); | ||
| 850 | } | ||
| 851 | |||
| 852 | static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp, u64 data) | ||
| 809 | { | 853 | { |
| 810 | u64 *spte; | 854 | u64 *spte; |
| 811 | int young = 0; | 855 | int young = 0; |
| @@ -841,13 +885,13 @@ static void rmap_recycle(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn) | |||
| 841 | gfn = unalias_gfn(vcpu->kvm, gfn); | 885 | gfn = unalias_gfn(vcpu->kvm, gfn); |
| 842 | rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level); | 886 | rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level); |
| 843 | 887 | ||
| 844 | kvm_unmap_rmapp(vcpu->kvm, rmapp); | 888 | kvm_unmap_rmapp(vcpu->kvm, rmapp, 0); |
| 845 | kvm_flush_remote_tlbs(vcpu->kvm); | 889 | kvm_flush_remote_tlbs(vcpu->kvm); |
| 846 | } | 890 | } |
| 847 | 891 | ||
| 848 | int kvm_age_hva(struct kvm *kvm, unsigned long hva) | 892 | int kvm_age_hva(struct kvm *kvm, unsigned long hva) |
| 849 | { | 893 | { |
| 850 | return kvm_handle_hva(kvm, hva, kvm_age_rmapp); | 894 | return kvm_handle_hva(kvm, hva, 0, kvm_age_rmapp); |
| 851 | } | 895 | } |
| 852 | 896 | ||
| 853 | #ifdef MMU_DEBUG | 897 | #ifdef MMU_DEBUG |
| @@ -1756,7 +1800,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, | |||
| 1756 | unsigned pte_access, int user_fault, | 1800 | unsigned pte_access, int user_fault, |
| 1757 | int write_fault, int dirty, int level, | 1801 | int write_fault, int dirty, int level, |
| 1758 | gfn_t gfn, pfn_t pfn, bool speculative, | 1802 | gfn_t gfn, pfn_t pfn, bool speculative, |
| 1759 | bool can_unsync) | 1803 | bool can_unsync, bool reset_host_protection) |
| 1760 | { | 1804 | { |
| 1761 | u64 spte; | 1805 | u64 spte; |
| 1762 | int ret = 0; | 1806 | int ret = 0; |
| @@ -1783,6 +1827,9 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, | |||
| 1783 | spte |= kvm_x86_ops->get_mt_mask(vcpu, gfn, | 1827 | spte |= kvm_x86_ops->get_mt_mask(vcpu, gfn, |
| 1784 | kvm_is_mmio_pfn(pfn)); | 1828 | kvm_is_mmio_pfn(pfn)); |
| 1785 | 1829 | ||
| 1830 | if (reset_host_protection) | ||
| 1831 | spte |= SPTE_HOST_WRITEABLE; | ||
| 1832 | |||
| 1786 | spte |= (u64)pfn << PAGE_SHIFT; | 1833 | spte |= (u64)pfn << PAGE_SHIFT; |
| 1787 | 1834 | ||
| 1788 | if ((pte_access & ACC_WRITE_MASK) | 1835 | if ((pte_access & ACC_WRITE_MASK) |
| @@ -1828,7 +1875,8 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, | |||
| 1828 | unsigned pt_access, unsigned pte_access, | 1875 | unsigned pt_access, unsigned pte_access, |
| 1829 | int user_fault, int write_fault, int dirty, | 1876 | int user_fault, int write_fault, int dirty, |
| 1830 | int *ptwrite, int level, gfn_t gfn, | 1877 | int *ptwrite, int level, gfn_t gfn, |
| 1831 | pfn_t pfn, bool speculative) | 1878 | pfn_t pfn, bool speculative, |
| 1879 | bool reset_host_protection) | ||
| 1832 | { | 1880 | { |
| 1833 | int was_rmapped = 0; | 1881 | int was_rmapped = 0; |
| 1834 | int was_writeble = is_writeble_pte(*sptep); | 1882 | int was_writeble = is_writeble_pte(*sptep); |
| @@ -1860,7 +1908,8 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, | |||
| 1860 | } | 1908 | } |
| 1861 | 1909 | ||
| 1862 | if (set_spte(vcpu, sptep, pte_access, user_fault, write_fault, | 1910 | if (set_spte(vcpu, sptep, pte_access, user_fault, write_fault, |
| 1863 | dirty, level, gfn, pfn, speculative, true)) { | 1911 | dirty, level, gfn, pfn, speculative, true, |
| 1912 | reset_host_protection)) { | ||
| 1864 | if (write_fault) | 1913 | if (write_fault) |
| 1865 | *ptwrite = 1; | 1914 | *ptwrite = 1; |
| 1866 | kvm_x86_ops->tlb_flush(vcpu); | 1915 | kvm_x86_ops->tlb_flush(vcpu); |
| @@ -1877,8 +1926,7 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, | |||
| 1877 | page_header_update_slot(vcpu->kvm, sptep, gfn); | 1926 | page_header_update_slot(vcpu->kvm, sptep, gfn); |
| 1878 | if (!was_rmapped) { | 1927 | if (!was_rmapped) { |
| 1879 | rmap_count = rmap_add(vcpu, sptep, gfn); | 1928 | rmap_count = rmap_add(vcpu, sptep, gfn); |
| 1880 | if (!is_rmap_spte(*sptep)) | 1929 | kvm_release_pfn_clean(pfn); |
| 1881 | kvm_release_pfn_clean(pfn); | ||
| 1882 | if (rmap_count > RMAP_RECYCLE_THRESHOLD) | 1930 | if (rmap_count > RMAP_RECYCLE_THRESHOLD) |
| 1883 | rmap_recycle(vcpu, sptep, gfn); | 1931 | rmap_recycle(vcpu, sptep, gfn); |
| 1884 | } else { | 1932 | } else { |
| @@ -1909,7 +1957,7 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write, | |||
| 1909 | if (iterator.level == level) { | 1957 | if (iterator.level == level) { |
| 1910 | mmu_set_spte(vcpu, iterator.sptep, ACC_ALL, ACC_ALL, | 1958 | mmu_set_spte(vcpu, iterator.sptep, ACC_ALL, ACC_ALL, |
| 1911 | 0, write, 1, &pt_write, | 1959 | 0, write, 1, &pt_write, |
| 1912 | level, gfn, pfn, false); | 1960 | level, gfn, pfn, false, true); |
| 1913 | ++vcpu->stat.pf_fixed; | 1961 | ++vcpu->stat.pf_fixed; |
| 1914 | break; | 1962 | break; |
| 1915 | } | 1963 | } |
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index d2fec9c12d22..72558f8ff3f5 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h | |||
| @@ -273,9 +273,13 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page, | |||
| 273 | if (mmu_notifier_retry(vcpu, vcpu->arch.update_pte.mmu_seq)) | 273 | if (mmu_notifier_retry(vcpu, vcpu->arch.update_pte.mmu_seq)) |
| 274 | return; | 274 | return; |
| 275 | kvm_get_pfn(pfn); | 275 | kvm_get_pfn(pfn); |
| 276 | /* | ||
| 277 | * we call mmu_set_spte() with reset_host_protection = true beacuse that | ||
| 278 | * vcpu->arch.update_pte.pfn was fetched from get_user_pages(write = 1). | ||
| 279 | */ | ||
| 276 | mmu_set_spte(vcpu, spte, page->role.access, pte_access, 0, 0, | 280 | mmu_set_spte(vcpu, spte, page->role.access, pte_access, 0, 0, |
| 277 | gpte & PT_DIRTY_MASK, NULL, PT_PAGE_TABLE_LEVEL, | 281 | gpte & PT_DIRTY_MASK, NULL, PT_PAGE_TABLE_LEVEL, |
| 278 | gpte_to_gfn(gpte), pfn, true); | 282 | gpte_to_gfn(gpte), pfn, true, true); |
| 279 | } | 283 | } |
| 280 | 284 | ||
| 281 | /* | 285 | /* |
| @@ -308,7 +312,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr, | |||
| 308 | user_fault, write_fault, | 312 | user_fault, write_fault, |
| 309 | gw->ptes[gw->level-1] & PT_DIRTY_MASK, | 313 | gw->ptes[gw->level-1] & PT_DIRTY_MASK, |
| 310 | ptwrite, level, | 314 | ptwrite, level, |
| 311 | gw->gfn, pfn, false); | 315 | gw->gfn, pfn, false, true); |
| 312 | break; | 316 | break; |
| 313 | } | 317 | } |
| 314 | 318 | ||
| @@ -558,6 +562,7 @@ static void FNAME(prefetch_page)(struct kvm_vcpu *vcpu, | |||
| 558 | static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) | 562 | static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) |
| 559 | { | 563 | { |
| 560 | int i, offset, nr_present; | 564 | int i, offset, nr_present; |
| 565 | bool reset_host_protection; | ||
| 561 | 566 | ||
| 562 | offset = nr_present = 0; | 567 | offset = nr_present = 0; |
| 563 | 568 | ||
| @@ -595,9 +600,16 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) | |||
| 595 | 600 | ||
| 596 | nr_present++; | 601 | nr_present++; |
| 597 | pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte); | 602 | pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte); |
| 603 | if (!(sp->spt[i] & SPTE_HOST_WRITEABLE)) { | ||
| 604 | pte_access &= ~ACC_WRITE_MASK; | ||
| 605 | reset_host_protection = 0; | ||
| 606 | } else { | ||
| 607 | reset_host_protection = 1; | ||
| 608 | } | ||
| 598 | set_spte(vcpu, &sp->spt[i], pte_access, 0, 0, | 609 | set_spte(vcpu, &sp->spt[i], pte_access, 0, 0, |
| 599 | is_dirty_gpte(gpte), PT_PAGE_TABLE_LEVEL, gfn, | 610 | is_dirty_gpte(gpte), PT_PAGE_TABLE_LEVEL, gfn, |
| 600 | spte_to_pfn(sp->spt[i]), true, false); | 611 | spte_to_pfn(sp->spt[i]), true, false, |
| 612 | reset_host_protection); | ||
| 601 | } | 613 | } |
| 602 | 614 | ||
| 603 | return !nr_present; | 615 | return !nr_present; |
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 944cc9c04b3c..c17404add91f 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
| @@ -767,6 +767,8 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | |||
| 767 | rdtscll(tsc_this); | 767 | rdtscll(tsc_this); |
| 768 | delta = vcpu->arch.host_tsc - tsc_this; | 768 | delta = vcpu->arch.host_tsc - tsc_this; |
| 769 | svm->vmcb->control.tsc_offset += delta; | 769 | svm->vmcb->control.tsc_offset += delta; |
| 770 | if (is_nested(svm)) | ||
| 771 | svm->nested.hsave->control.tsc_offset += delta; | ||
| 770 | vcpu->cpu = cpu; | 772 | vcpu->cpu = cpu; |
| 771 | kvm_migrate_timers(vcpu); | 773 | kvm_migrate_timers(vcpu); |
| 772 | svm->asid_generation = 0; | 774 | svm->asid_generation = 0; |
| @@ -2057,10 +2059,14 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data) | |||
| 2057 | 2059 | ||
| 2058 | switch (ecx) { | 2060 | switch (ecx) { |
| 2059 | case MSR_IA32_TSC: { | 2061 | case MSR_IA32_TSC: { |
| 2060 | u64 tsc; | 2062 | u64 tsc_offset; |
| 2063 | |||
| 2064 | if (is_nested(svm)) | ||
| 2065 | tsc_offset = svm->nested.hsave->control.tsc_offset; | ||
| 2066 | else | ||
| 2067 | tsc_offset = svm->vmcb->control.tsc_offset; | ||
| 2061 | 2068 | ||
| 2062 | rdtscll(tsc); | 2069 | *data = tsc_offset + native_read_tsc(); |
| 2063 | *data = svm->vmcb->control.tsc_offset + tsc; | ||
| 2064 | break; | 2070 | break; |
| 2065 | } | 2071 | } |
| 2066 | case MSR_K6_STAR: | 2072 | case MSR_K6_STAR: |
| @@ -2146,10 +2152,17 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data) | |||
| 2146 | 2152 | ||
| 2147 | switch (ecx) { | 2153 | switch (ecx) { |
| 2148 | case MSR_IA32_TSC: { | 2154 | case MSR_IA32_TSC: { |
| 2149 | u64 tsc; | 2155 | u64 tsc_offset = data - native_read_tsc(); |
| 2156 | u64 g_tsc_offset = 0; | ||
| 2157 | |||
| 2158 | if (is_nested(svm)) { | ||
| 2159 | g_tsc_offset = svm->vmcb->control.tsc_offset - | ||
| 2160 | svm->nested.hsave->control.tsc_offset; | ||
| 2161 | svm->nested.hsave->control.tsc_offset = tsc_offset; | ||
| 2162 | } | ||
| 2163 | |||
| 2164 | svm->vmcb->control.tsc_offset = tsc_offset + g_tsc_offset; | ||
| 2150 | 2165 | ||
| 2151 | rdtscll(tsc); | ||
| 2152 | svm->vmcb->control.tsc_offset = data - tsc; | ||
| 2153 | break; | 2166 | break; |
| 2154 | } | 2167 | } |
| 2155 | case MSR_K6_STAR: | 2168 | case MSR_K6_STAR: |
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index f3812014bd0b..ed53b42caba1 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
| @@ -709,7 +709,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | |||
| 709 | if (vcpu->cpu != cpu) { | 709 | if (vcpu->cpu != cpu) { |
| 710 | vcpu_clear(vmx); | 710 | vcpu_clear(vmx); |
| 711 | kvm_migrate_timers(vcpu); | 711 | kvm_migrate_timers(vcpu); |
| 712 | vpid_sync_vcpu_all(vmx); | 712 | set_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests); |
| 713 | local_irq_disable(); | 713 | local_irq_disable(); |
| 714 | list_add(&vmx->local_vcpus_link, | 714 | list_add(&vmx->local_vcpus_link, |
| 715 | &per_cpu(vcpus_on_cpu, cpu)); | 715 | &per_cpu(vcpus_on_cpu, cpu)); |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index be451ee44249..9b9695322f56 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
| @@ -1591,6 +1591,8 @@ static int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid, | |||
| 1591 | 1591 | ||
| 1592 | if (cpuid->nent < 1) | 1592 | if (cpuid->nent < 1) |
| 1593 | goto out; | 1593 | goto out; |
| 1594 | if (cpuid->nent > KVM_MAX_CPUID_ENTRIES) | ||
| 1595 | cpuid->nent = KVM_MAX_CPUID_ENTRIES; | ||
| 1594 | r = -ENOMEM; | 1596 | r = -ENOMEM; |
| 1595 | cpuid_entries = vmalloc(sizeof(struct kvm_cpuid_entry2) * cpuid->nent); | 1597 | cpuid_entries = vmalloc(sizeof(struct kvm_cpuid_entry2) * cpuid->nent); |
| 1596 | if (!cpuid_entries) | 1598 | if (!cpuid_entries) |
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index e79c54034bcd..b7c78a403dc2 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
| @@ -850,6 +850,19 @@ static void kvm_mmu_notifier_invalidate_page(struct mmu_notifier *mn, | |||
| 850 | 850 | ||
| 851 | } | 851 | } |
| 852 | 852 | ||
| 853 | static void kvm_mmu_notifier_change_pte(struct mmu_notifier *mn, | ||
| 854 | struct mm_struct *mm, | ||
| 855 | unsigned long address, | ||
| 856 | pte_t pte) | ||
| 857 | { | ||
| 858 | struct kvm *kvm = mmu_notifier_to_kvm(mn); | ||
| 859 | |||
| 860 | spin_lock(&kvm->mmu_lock); | ||
| 861 | kvm->mmu_notifier_seq++; | ||
| 862 | kvm_set_spte_hva(kvm, address, pte); | ||
| 863 | spin_unlock(&kvm->mmu_lock); | ||
| 864 | } | ||
| 865 | |||
| 853 | static void kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn, | 866 | static void kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn, |
| 854 | struct mm_struct *mm, | 867 | struct mm_struct *mm, |
| 855 | unsigned long start, | 868 | unsigned long start, |
| @@ -929,6 +942,7 @@ static const struct mmu_notifier_ops kvm_mmu_notifier_ops = { | |||
| 929 | .invalidate_range_start = kvm_mmu_notifier_invalidate_range_start, | 942 | .invalidate_range_start = kvm_mmu_notifier_invalidate_range_start, |
| 930 | .invalidate_range_end = kvm_mmu_notifier_invalidate_range_end, | 943 | .invalidate_range_end = kvm_mmu_notifier_invalidate_range_end, |
| 931 | .clear_flush_young = kvm_mmu_notifier_clear_flush_young, | 944 | .clear_flush_young = kvm_mmu_notifier_clear_flush_young, |
| 945 | .change_pte = kvm_mmu_notifier_change_pte, | ||
| 932 | .release = kvm_mmu_notifier_release, | 946 | .release = kvm_mmu_notifier_release, |
| 933 | }; | 947 | }; |
| 934 | #endif /* CONFIG_MMU_NOTIFIER && KVM_ARCH_WANT_MMU_NOTIFIER */ | 948 | #endif /* CONFIG_MMU_NOTIFIER && KVM_ARCH_WANT_MMU_NOTIFIER */ |
