diff options
Diffstat (limited to 'arch/x86/kvm/mmu.c')
-rw-r--r-- | arch/x86/kvm/mmu.c | 91 |
1 files changed, 73 insertions, 18 deletions
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 0bff4d54817e..8b750ff6911a 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
@@ -49,15 +49,21 @@ | |||
49 | */ | 49 | */ |
50 | bool tdp_enabled = false; | 50 | bool tdp_enabled = false; |
51 | 51 | ||
52 | #undef MMU_DEBUG | 52 | enum { |
53 | AUDIT_PRE_PAGE_FAULT, | ||
54 | AUDIT_POST_PAGE_FAULT, | ||
55 | AUDIT_PRE_PTE_WRITE, | ||
56 | AUDIT_POST_PTE_WRITE | ||
57 | }; | ||
53 | 58 | ||
54 | #undef AUDIT | 59 | char *audit_point_name[] = { |
60 | "pre page fault", | ||
61 | "post page fault", | ||
62 | "pre pte write", | ||
63 | "post pte write" | ||
64 | }; | ||
55 | 65 | ||
56 | #ifdef AUDIT | 66 | #undef MMU_DEBUG |
57 | static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg); | ||
58 | #else | ||
59 | static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) {} | ||
60 | #endif | ||
61 | 67 | ||
62 | #ifdef MMU_DEBUG | 68 | #ifdef MMU_DEBUG |
63 | 69 | ||
@@ -71,7 +77,7 @@ static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) {} | |||
71 | 77 | ||
72 | #endif | 78 | #endif |
73 | 79 | ||
74 | #if defined(MMU_DEBUG) || defined(AUDIT) | 80 | #ifdef MMU_DEBUG |
75 | static int dbg = 0; | 81 | static int dbg = 0; |
76 | module_param(dbg, bool, 0644); | 82 | module_param(dbg, bool, 0644); |
77 | #endif | 83 | #endif |
@@ -2964,7 +2970,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | |||
2964 | kvm_mmu_access_page(vcpu, gfn); | 2970 | kvm_mmu_access_page(vcpu, gfn); |
2965 | kvm_mmu_free_some_pages(vcpu); | 2971 | kvm_mmu_free_some_pages(vcpu); |
2966 | ++vcpu->kvm->stat.mmu_pte_write; | 2972 | ++vcpu->kvm->stat.mmu_pte_write; |
2967 | kvm_mmu_audit(vcpu, "pre pte write"); | 2973 | trace_kvm_mmu_audit(vcpu, AUDIT_PRE_PTE_WRITE); |
2968 | if (guest_initiated) { | 2974 | if (guest_initiated) { |
2969 | if (gfn == vcpu->arch.last_pt_write_gfn | 2975 | if (gfn == vcpu->arch.last_pt_write_gfn |
2970 | && !last_updated_pte_accessed(vcpu)) { | 2976 | && !last_updated_pte_accessed(vcpu)) { |
@@ -3037,7 +3043,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, | |||
3037 | } | 3043 | } |
3038 | mmu_pte_write_flush_tlb(vcpu, zap_page, remote_flush, local_flush); | 3044 | mmu_pte_write_flush_tlb(vcpu, zap_page, remote_flush, local_flush); |
3039 | kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list); | 3045 | kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list); |
3040 | kvm_mmu_audit(vcpu, "post pte write"); | 3046 | trace_kvm_mmu_audit(vcpu, AUDIT_POST_PTE_WRITE); |
3041 | spin_unlock(&vcpu->kvm->mmu_lock); | 3047 | spin_unlock(&vcpu->kvm->mmu_lock); |
3042 | if (!is_error_pfn(vcpu->arch.update_pte.pfn)) { | 3048 | if (!is_error_pfn(vcpu->arch.update_pte.pfn)) { |
3043 | kvm_release_pfn_clean(vcpu->arch.update_pte.pfn); | 3049 | kvm_release_pfn_clean(vcpu->arch.update_pte.pfn); |
@@ -3483,8 +3489,7 @@ int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 sptes[4]) | |||
3483 | } | 3489 | } |
3484 | EXPORT_SYMBOL_GPL(kvm_mmu_get_spte_hierarchy); | 3490 | EXPORT_SYMBOL_GPL(kvm_mmu_get_spte_hierarchy); |
3485 | 3491 | ||
3486 | #ifdef AUDIT | 3492 | #ifdef CONFIG_KVM_MMU_AUDIT |
3487 | |||
3488 | static const char *audit_msg; | 3493 | static const char *audit_msg; |
3489 | 3494 | ||
3490 | typedef void (*inspect_spte_fn) (struct kvm *kvm, u64 *sptep); | 3495 | typedef void (*inspect_spte_fn) (struct kvm *kvm, u64 *sptep); |
@@ -3699,18 +3704,68 @@ static void audit_write_protection(struct kvm_vcpu *vcpu) | |||
3699 | } | 3704 | } |
3700 | } | 3705 | } |
3701 | 3706 | ||
3702 | static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) | 3707 | static void kvm_mmu_audit(void *ignore, struct kvm_vcpu *vcpu, int audit_point) |
3703 | { | 3708 | { |
3704 | int olddbg = dbg; | 3709 | audit_msg = audit_point_name[audit_point]; |
3705 | |||
3706 | dbg = 0; | ||
3707 | audit_msg = msg; | ||
3708 | audit_rmap(vcpu); | 3710 | audit_rmap(vcpu); |
3709 | audit_write_protection(vcpu); | 3711 | audit_write_protection(vcpu); |
3710 | if (strcmp("pre pte write", audit_msg) != 0) | 3712 | if (strcmp("pre pte write", audit_msg) != 0) |
3711 | audit_mappings(vcpu); | 3713 | audit_mappings(vcpu); |
3712 | audit_sptes_have_rmaps(vcpu); | 3714 | audit_sptes_have_rmaps(vcpu); |
3713 | dbg = olddbg; | ||
3714 | } | 3715 | } |
3715 | 3716 | ||
3717 | static bool mmu_audit; | ||
3718 | |||
3719 | static void mmu_audit_enable(void) | ||
3720 | { | ||
3721 | int ret; | ||
3722 | |||
3723 | if (mmu_audit) | ||
3724 | return; | ||
3725 | |||
3726 | ret = register_trace_kvm_mmu_audit(kvm_mmu_audit, NULL); | ||
3727 | WARN_ON(ret); | ||
3728 | |||
3729 | mmu_audit = true; | ||
3730 | } | ||
3731 | |||
3732 | static void mmu_audit_disable(void) | ||
3733 | { | ||
3734 | if (!mmu_audit) | ||
3735 | return; | ||
3736 | |||
3737 | unregister_trace_kvm_mmu_audit(kvm_mmu_audit, NULL); | ||
3738 | tracepoint_synchronize_unregister(); | ||
3739 | mmu_audit = false; | ||
3740 | } | ||
3741 | |||
3742 | static int mmu_audit_set(const char *val, const struct kernel_param *kp) | ||
3743 | { | ||
3744 | int ret; | ||
3745 | unsigned long enable; | ||
3746 | |||
3747 | ret = strict_strtoul(val, 10, &enable); | ||
3748 | if (ret < 0) | ||
3749 | return -EINVAL; | ||
3750 | |||
3751 | switch (enable) { | ||
3752 | case 0: | ||
3753 | mmu_audit_disable(); | ||
3754 | break; | ||
3755 | case 1: | ||
3756 | mmu_audit_enable(); | ||
3757 | break; | ||
3758 | default: | ||
3759 | return -EINVAL; | ||
3760 | } | ||
3761 | |||
3762 | return 0; | ||
3763 | } | ||
3764 | |||
3765 | static struct kernel_param_ops audit_param_ops = { | ||
3766 | .set = mmu_audit_set, | ||
3767 | .get = param_get_bool, | ||
3768 | }; | ||
3769 | |||
3770 | module_param_cb(mmu_audit, &audit_param_ops, &mmu_audit, 0644); | ||
3716 | #endif | 3771 | #endif |