aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kvm/mmu.c75
-rw-r--r--include/linux/kvm_host.h1
-rw-r--r--virt/kvm/kvm_main.c15
3 files changed, 54 insertions, 37 deletions
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 68575dc32ec7..0d91f60af1a8 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -3487,15 +3487,6 @@ EXPORT_SYMBOL_GPL(kvm_mmu_get_spte_hierarchy);
3487 3487
3488static const char *audit_msg; 3488static const char *audit_msg;
3489 3489
3490static gva_t canonicalize(gva_t gva)
3491{
3492#ifdef CONFIG_X86_64
3493 gva = (long long)(gva << 16) >> 16;
3494#endif
3495 return gva;
3496}
3497
3498
3499typedef void (*inspect_spte_fn) (struct kvm *kvm, u64 *sptep); 3490typedef void (*inspect_spte_fn) (struct kvm *kvm, u64 *sptep);
3500 3491
3501static void __mmu_spte_walk(struct kvm *kvm, struct kvm_mmu_page *sp, 3492static void __mmu_spte_walk(struct kvm *kvm, struct kvm_mmu_page *sp,
@@ -3550,39 +3541,53 @@ static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte,
3550 gva_t va_delta = 1ul << (PAGE_SHIFT + 9 * (level - 1)); 3541 gva_t va_delta = 1ul << (PAGE_SHIFT + 9 * (level - 1));
3551 3542
3552 for (i = 0; i < PT64_ENT_PER_PAGE; ++i, va += va_delta) { 3543 for (i = 0; i < PT64_ENT_PER_PAGE; ++i, va += va_delta) {
3553 u64 ent = pt[i]; 3544 u64 *sptep = pt + i;
3545 struct kvm_mmu_page *sp;
3546 gfn_t gfn;
3547 pfn_t pfn;
3548 hpa_t hpa;
3554 3549
3555 if (ent == shadow_trap_nonpresent_pte) 3550 sp = page_header(__pa(sptep));
3556 continue;
3557 3551
3558 va = canonicalize(va); 3552 if (sp->unsync) {
3559 if (is_shadow_present_pte(ent) && !is_last_spte(ent, level)) 3553 if (level != PT_PAGE_TABLE_LEVEL) {
3560 audit_mappings_page(vcpu, ent, va, level - 1); 3554 printk(KERN_ERR "audit: (%s) error: unsync sp: %p level = %d\n",
3561 else { 3555 audit_msg, sp, level);
3562 gpa_t gpa = kvm_mmu_gva_to_gpa_read(vcpu, va, NULL); 3556 return;
3563 gfn_t gfn = gpa >> PAGE_SHIFT; 3557 }
3564 pfn_t pfn = gfn_to_pfn(vcpu->kvm, gfn);
3565 hpa_t hpa = (hpa_t)pfn << PAGE_SHIFT;
3566 3558
3567 if (is_error_pfn(pfn)) { 3559 if (*sptep == shadow_notrap_nonpresent_pte) {
3568 kvm_release_pfn_clean(pfn); 3560 printk(KERN_ERR "audit: (%s) error: notrap spte in unsync sp: %p\n",
3569 continue; 3561 audit_msg, sp);
3562 return;
3570 } 3563 }
3564 }
3571 3565
3572 if (is_shadow_present_pte(ent) 3566 if (sp->role.direct && *sptep == shadow_notrap_nonpresent_pte) {
3573 && (ent & PT64_BASE_ADDR_MASK) != hpa) 3567 printk(KERN_ERR "audit: (%s) error: notrap spte in direct sp: %p\n",
3574 printk(KERN_ERR "xx audit error: (%s) levels %d" 3568 audit_msg, sp);
3575 " gva %lx gpa %llx hpa %llx ent %llx %d\n", 3569 return;
3576 audit_msg, vcpu->arch.mmu.root_level, 3570 }
3577 va, gpa, hpa, ent, 3571
3578 is_shadow_present_pte(ent)); 3572 if (!is_shadow_present_pte(*sptep) ||
3579 else if (ent == shadow_notrap_nonpresent_pte 3573 !is_last_spte(*sptep, level))
3580 && !is_error_hpa(hpa)) 3574 return;
3581 printk(KERN_ERR "audit: (%s) notrap shadow," 3575
3582 " valid guest gva %lx\n", audit_msg, va); 3576 gfn = kvm_mmu_page_get_gfn(sp, sptep - sp->spt);
3583 kvm_release_pfn_clean(pfn); 3577 pfn = gfn_to_pfn_atomic(vcpu->kvm, gfn);
3584 3578
3579 if (is_error_pfn(pfn)) {
3580 kvm_release_pfn_clean(pfn);
3581 return;
3585 } 3582 }
3583
3584 hpa = pfn << PAGE_SHIFT;
3585
3586 if ((*sptep & PT64_BASE_ADDR_MASK) != hpa)
3587 printk(KERN_ERR "xx audit error: (%s) levels %d"
3588 " gva %lx pfn %llx hpa %llx ent %llxn",
3589 audit_msg, vcpu->arch.mmu.root_level,
3590 va, pfn, hpa, *sptep);
3586 } 3591 }
3587} 3592}
3588 3593
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index b837ec80885d..f2ecdd52032b 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -300,6 +300,7 @@ void kvm_set_page_dirty(struct page *page);
300void kvm_set_page_accessed(struct page *page); 300void kvm_set_page_accessed(struct page *page);
301 301
302pfn_t hva_to_pfn_atomic(struct kvm *kvm, unsigned long addr); 302pfn_t hva_to_pfn_atomic(struct kvm *kvm, unsigned long addr);
303pfn_t gfn_to_pfn_atomic(struct kvm *kvm, gfn_t gfn);
303pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn); 304pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn);
304pfn_t gfn_to_pfn_memslot(struct kvm *kvm, 305pfn_t gfn_to_pfn_memslot(struct kvm *kvm,
305 struct kvm_memory_slot *slot, gfn_t gfn); 306 struct kvm_memory_slot *slot, gfn_t gfn);
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 2eb0b7500a2a..c7a57b4feb39 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -999,7 +999,7 @@ pfn_t hva_to_pfn_atomic(struct kvm *kvm, unsigned long addr)
999} 999}
1000EXPORT_SYMBOL_GPL(hva_to_pfn_atomic); 1000EXPORT_SYMBOL_GPL(hva_to_pfn_atomic);
1001 1001
1002pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn) 1002static pfn_t __gfn_to_pfn(struct kvm *kvm, gfn_t gfn, bool atomic)
1003{ 1003{
1004 unsigned long addr; 1004 unsigned long addr;
1005 1005
@@ -1009,7 +1009,18 @@ pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn)
1009 return page_to_pfn(bad_page); 1009 return page_to_pfn(bad_page);
1010 } 1010 }
1011 1011
1012 return hva_to_pfn(kvm, addr, false); 1012 return hva_to_pfn(kvm, addr, atomic);
1013}
1014
1015pfn_t gfn_to_pfn_atomic(struct kvm *kvm, gfn_t gfn)
1016{
1017 return __gfn_to_pfn(kvm, gfn, true);
1018}
1019EXPORT_SYMBOL_GPL(gfn_to_pfn_atomic);
1020
1021pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn)
1022{
1023 return __gfn_to_pfn(kvm, gfn, false);
1013} 1024}
1014EXPORT_SYMBOL_GPL(gfn_to_pfn); 1025EXPORT_SYMBOL_GPL(gfn_to_pfn);
1015 1026