mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-26 16:41:25 +00:00
KVM: MMU: support disable/enable mmu audit dynamicly
Add a r/w module parameter named 'mmu_audit', it can control audit enable/disable: enable: echo 1 > /sys/module/kvm/parameters/mmu_audit disable: echo 0 > /sys/module/kvm/parameters/mmu_audit This patch not change the logic Signed-off-by: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com> Signed-off-by: Avi Kivity <avi@redhat.com>
This commit is contained in:
parent
84e0cefa8d
commit
8b1fe17cc7
4 changed files with 102 additions and 21 deletions
|
@ -64,6 +64,13 @@ config KVM_AMD
|
||||||
To compile this as a module, choose M here: the module
|
To compile this as a module, choose M here: the module
|
||||||
will be called kvm-amd.
|
will be called kvm-amd.
|
||||||
|
|
||||||
|
config KVM_MMU_AUDIT
|
||||||
|
bool "Audit KVM MMU"
|
||||||
|
depends on KVM && TRACEPOINTS
|
||||||
|
---help---
|
||||||
|
This option adds a R/W kVM module parameter 'mmu_audit', which allows
|
||||||
|
audit KVM MMU at runtime.
|
||||||
|
|
||||||
# OK, it's a little counter-intuitive to do this, but it puts it neatly under
|
# OK, it's a little counter-intuitive to do this, but it puts it neatly under
|
||||||
# the virtualization menu.
|
# the virtualization menu.
|
||||||
source drivers/vhost/Kconfig
|
source drivers/vhost/Kconfig
|
||||||
|
|
|
@ -49,16 +49,22 @@
|
||||||
*/
|
*/
|
||||||
bool tdp_enabled = false;
|
bool tdp_enabled = false;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
AUDIT_PRE_PAGE_FAULT,
|
||||||
|
AUDIT_POST_PAGE_FAULT,
|
||||||
|
AUDIT_PRE_PTE_WRITE,
|
||||||
|
AUDIT_POST_PTE_WRITE
|
||||||
|
};
|
||||||
|
|
||||||
|
char *audit_point_name[] = {
|
||||||
|
"pre page fault",
|
||||||
|
"post page fault",
|
||||||
|
"pre pte write",
|
||||||
|
"post pte write"
|
||||||
|
};
|
||||||
|
|
||||||
#undef MMU_DEBUG
|
#undef MMU_DEBUG
|
||||||
|
|
||||||
#undef AUDIT
|
|
||||||
|
|
||||||
#ifdef AUDIT
|
|
||||||
static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg);
|
|
||||||
#else
|
|
||||||
static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef MMU_DEBUG
|
#ifdef MMU_DEBUG
|
||||||
|
|
||||||
#define pgprintk(x...) do { if (dbg) printk(x); } while (0)
|
#define pgprintk(x...) do { if (dbg) printk(x); } while (0)
|
||||||
|
@ -71,7 +77,7 @@ static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) {}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(MMU_DEBUG) || defined(AUDIT)
|
#ifdef MMU_DEBUG
|
||||||
static int dbg = 0;
|
static int dbg = 0;
|
||||||
module_param(dbg, bool, 0644);
|
module_param(dbg, bool, 0644);
|
||||||
#endif
|
#endif
|
||||||
|
@ -2964,7 +2970,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
|
||||||
kvm_mmu_access_page(vcpu, gfn);
|
kvm_mmu_access_page(vcpu, gfn);
|
||||||
kvm_mmu_free_some_pages(vcpu);
|
kvm_mmu_free_some_pages(vcpu);
|
||||||
++vcpu->kvm->stat.mmu_pte_write;
|
++vcpu->kvm->stat.mmu_pte_write;
|
||||||
kvm_mmu_audit(vcpu, "pre pte write");
|
trace_kvm_mmu_audit(vcpu, AUDIT_PRE_PTE_WRITE);
|
||||||
if (guest_initiated) {
|
if (guest_initiated) {
|
||||||
if (gfn == vcpu->arch.last_pt_write_gfn
|
if (gfn == vcpu->arch.last_pt_write_gfn
|
||||||
&& !last_updated_pte_accessed(vcpu)) {
|
&& !last_updated_pte_accessed(vcpu)) {
|
||||||
|
@ -3037,7 +3043,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
|
||||||
}
|
}
|
||||||
mmu_pte_write_flush_tlb(vcpu, zap_page, remote_flush, local_flush);
|
mmu_pte_write_flush_tlb(vcpu, zap_page, remote_flush, local_flush);
|
||||||
kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
|
kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
|
||||||
kvm_mmu_audit(vcpu, "post pte write");
|
trace_kvm_mmu_audit(vcpu, AUDIT_POST_PTE_WRITE);
|
||||||
spin_unlock(&vcpu->kvm->mmu_lock);
|
spin_unlock(&vcpu->kvm->mmu_lock);
|
||||||
if (!is_error_pfn(vcpu->arch.update_pte.pfn)) {
|
if (!is_error_pfn(vcpu->arch.update_pte.pfn)) {
|
||||||
kvm_release_pfn_clean(vcpu->arch.update_pte.pfn);
|
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])
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(kvm_mmu_get_spte_hierarchy);
|
EXPORT_SYMBOL_GPL(kvm_mmu_get_spte_hierarchy);
|
||||||
|
|
||||||
#ifdef AUDIT
|
#ifdef CONFIG_KVM_MMU_AUDIT
|
||||||
|
|
||||||
static const char *audit_msg;
|
static const char *audit_msg;
|
||||||
|
|
||||||
typedef void (*inspect_spte_fn) (struct kvm *kvm, u64 *sptep);
|
typedef void (*inspect_spte_fn) (struct kvm *kvm, u64 *sptep);
|
||||||
|
@ -3699,18 +3704,68 @@ static void audit_write_protection(struct kvm_vcpu *vcpu)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg)
|
static void kvm_mmu_audit(void *ignore, struct kvm_vcpu *vcpu, int audit_point)
|
||||||
{
|
{
|
||||||
int olddbg = dbg;
|
audit_msg = audit_point_name[audit_point];
|
||||||
|
|
||||||
dbg = 0;
|
|
||||||
audit_msg = msg;
|
|
||||||
audit_rmap(vcpu);
|
audit_rmap(vcpu);
|
||||||
audit_write_protection(vcpu);
|
audit_write_protection(vcpu);
|
||||||
if (strcmp("pre pte write", audit_msg) != 0)
|
if (strcmp("pre pte write", audit_msg) != 0)
|
||||||
audit_mappings(vcpu);
|
audit_mappings(vcpu);
|
||||||
audit_sptes_have_rmaps(vcpu);
|
audit_sptes_have_rmaps(vcpu);
|
||||||
dbg = olddbg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool mmu_audit;
|
||||||
|
|
||||||
|
static void mmu_audit_enable(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (mmu_audit)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ret = register_trace_kvm_mmu_audit(kvm_mmu_audit, NULL);
|
||||||
|
WARN_ON(ret);
|
||||||
|
|
||||||
|
mmu_audit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mmu_audit_disable(void)
|
||||||
|
{
|
||||||
|
if (!mmu_audit)
|
||||||
|
return;
|
||||||
|
|
||||||
|
unregister_trace_kvm_mmu_audit(kvm_mmu_audit, NULL);
|
||||||
|
tracepoint_synchronize_unregister();
|
||||||
|
mmu_audit = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mmu_audit_set(const char *val, const struct kernel_param *kp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
unsigned long enable;
|
||||||
|
|
||||||
|
ret = strict_strtoul(val, 10, &enable);
|
||||||
|
if (ret < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
switch (enable) {
|
||||||
|
case 0:
|
||||||
|
mmu_audit_disable();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
mmu_audit_enable();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct kernel_param_ops audit_param_ops = {
|
||||||
|
.set = mmu_audit_set,
|
||||||
|
.get = param_get_bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_param_cb(mmu_audit, &audit_param_ops, &mmu_audit, 0644);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -195,6 +195,25 @@ DEFINE_EVENT(kvm_mmu_page_class, kvm_mmu_prepare_zap_page,
|
||||||
|
|
||||||
TP_ARGS(sp)
|
TP_ARGS(sp)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
TRACE_EVENT(
|
||||||
|
kvm_mmu_audit,
|
||||||
|
TP_PROTO(struct kvm_vcpu *vcpu, int audit_point),
|
||||||
|
TP_ARGS(vcpu, audit_point),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field(struct kvm_vcpu *, vcpu)
|
||||||
|
__field(int, audit_point)
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
__entry->vcpu = vcpu;
|
||||||
|
__entry->audit_point = audit_point;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk("vcpu:%d %s", __entry->vcpu->cpu,
|
||||||
|
audit_point_name[__entry->audit_point])
|
||||||
|
);
|
||||||
#endif /* _TRACE_KVMMMU_H */
|
#endif /* _TRACE_KVMMMU_H */
|
||||||
|
|
||||||
#undef TRACE_INCLUDE_PATH
|
#undef TRACE_INCLUDE_PATH
|
||||||
|
|
|
@ -542,7 +542,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
|
||||||
if (mmu_notifier_retry(vcpu, mmu_seq))
|
if (mmu_notifier_retry(vcpu, mmu_seq))
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
kvm_mmu_audit(vcpu, "pre page fault");
|
trace_kvm_mmu_audit(vcpu, AUDIT_PRE_PAGE_FAULT);
|
||||||
kvm_mmu_free_some_pages(vcpu);
|
kvm_mmu_free_some_pages(vcpu);
|
||||||
sptep = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault,
|
sptep = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault,
|
||||||
level, &write_pt, pfn);
|
level, &write_pt, pfn);
|
||||||
|
@ -554,7 +554,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
|
||||||
vcpu->arch.last_pt_write_count = 0; /* reset fork detector */
|
vcpu->arch.last_pt_write_count = 0; /* reset fork detector */
|
||||||
|
|
||||||
++vcpu->stat.pf_fixed;
|
++vcpu->stat.pf_fixed;
|
||||||
kvm_mmu_audit(vcpu, "post page fault (fixed)");
|
trace_kvm_mmu_audit(vcpu, AUDIT_POST_PAGE_FAULT);
|
||||||
spin_unlock(&vcpu->kvm->mmu_lock);
|
spin_unlock(&vcpu->kvm->mmu_lock);
|
||||||
|
|
||||||
return write_pt;
|
return write_pt;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue